<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 5.4.0">
  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">
  <meta name="google-site-verification" content="d44tDfSSWxm1_XP1dAq65hkgyD6zw70Ua9JdCaJqWGg">

<link rel="stylesheet" href="/css/main.css">


<link rel="stylesheet" href="/lib/font-awesome/css/all.min.css">

<script id="hexo-configurations">
    var NexT = window.NexT || {};
    var CONFIG = {"hostname":"zasdfgbnm.github.io","root":"/","scheme":"Muse","version":"7.8.0","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12,"onmobile":false},"copycode":{"enable":false,"show_result":false,"style":null},"back2top":{"enable":true,"sidebar":false,"scrollpercent":false},"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":false,"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"algolia":{"hits":{"per_page":10},"labels":{"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}},"localsearch":{"enable":false,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}}};
  </script>

  <meta name="description" content="IntroductionI’m recently writing something that uses Linux’s firewall framework to do some non-standard operations packets. Extending the kernel is required for my task but unfortunately documentation">
<meta property="og:type" content="article">
<meta property="og:title" content="Adding new expressions to nftables">
<meta property="og:url" content="https://zasdfgbnm.github.io/2017/09/07/Extending-nftables/index.html">
<meta property="og:site_name" content="zasdfgbnm">
<meta property="og:description" content="IntroductionI’m recently writing something that uses Linux’s firewall framework to do some non-standard operations packets. Extending the kernel is required for my task but unfortunately documentation">
<meta property="og:locale" content="en_US">
<meta property="article:published_time" content="2017-09-07T19:50:12.000Z">
<meta property="article:modified_time" content="2021-04-04T05:17:59.763Z">
<meta property="article:author" content="zasdfgbnm">
<meta property="article:tag" content="Linux">
<meta property="article:tag" content="Kernel">
<meta property="article:tag" content="nftables">
<meta property="article:tag" content="network">
<meta property="article:tag" content="netfilter">
<meta name="twitter:card" content="summary">

<link rel="canonical" href="https://zasdfgbnm.github.io/2017/09/07/Extending-nftables/">


<script id="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome : false,
    isPost : true,
    lang   : 'en'
  };
</script>

  <title>Adding new expressions to nftables | zasdfgbnm</title>
  
    <script async src="https://www.googletagmanager.com/gtag/js?id=UA-7583294-5"></script>
    <script>
      if (CONFIG.hostname === location.hostname) {
        window.dataLayer = window.dataLayer || [];
        function gtag(){dataLayer.push(arguments);}
        gtag('js', new Date());
        gtag('config', 'UA-7583294-5');
      }
    </script>


  <script>
    var _hmt = _hmt || [];
    (function() {
      var hm = document.createElement("script");
      hm.src = "https://hm.baidu.com/hm.js?a56abdeb557a286a6b7a104348fdfbcd";
      var s = document.getElementsByTagName("script")[0];
      s.parentNode.insertBefore(hm, s);
    })();
  </script>




  <noscript>
  <style>
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

<link rel="alternate" href="/atom.xml" title="zasdfgbnm" type="application/atom+xml">
</head>

<body itemscope itemtype="http://schema.org/WebPage">
  <div class="container use-motion">
    <div class="headband"></div>

    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="Toggle navigation bar">
      <span class="toggle-line toggle-line-first"></span>
      <span class="toggle-line toggle-line-middle"></span>
      <span class="toggle-line toggle-line-last"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <h1 class="site-title">zasdfgbnm</h1>
      <span class="logo-line-after"><i></i></span>
    </a>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
    </div>
  </div>
</div>




<nav class="site-nav">
  <ul id="menu" class="main-menu menu">
        <li class="menu-item menu-item-home">

    <a href="/" rel="section"><i class="fa fa-home fa-fw"></i>Home</a>

  </li>
        <li class="menu-item menu-item-archives">

    <a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>Archives</a>

  </li>
        <li class="menu-item menu-item-about">

    <a href="/about/" rel="section"><i class="fa fa-user fa-fw"></i>About</a>

  </li>
        <li class="menu-item menu-item-tags">

    <a href="/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>Tags</a>

  </li>
        <li class="menu-item menu-item-categories">

    <a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>Categories</a>

  </li>
        <li class="menu-item menu-item-sitemap">

    <a href="/sitemap.xml" rel="section"><i class="fa fa-sitemap fa-fw"></i>Sitemap</a>

  </li>
  </ul>
</nav>




</div>
    </header>

    
  <div class="back-to-top">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>


    <main class="main">
      <div class="main-inner">
        <div class="content-wrap">
          

          <div class="content post posts-expand">
            

    
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="en">
    <link itemprop="mainEntityOfPage" href="https://zasdfgbnm.github.io/2017/09/07/Extending-nftables/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="zasdfgbnm">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="zasdfgbnm">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          Adding new expressions to nftables
        </h1>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">Posted on</span>

              <time title="Created: 2017-09-07 15:50:12" itemprop="dateCreated datePublished" datetime="2017-09-07T15:50:12-04:00">2017-09-07</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">Edited on</span>
                <time title="Modified: 2021-04-04 01:17:59" itemprop="dateModified" datetime="2021-04-04T01:17:59-04:00">2021-04-04</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">In</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Linux/" itemprop="url" rel="index"><span itemprop="name">Linux</span></a>
                </span>
            </span>

          
  
  <span class="post-meta-item">
    
      <span class="post-meta-item-icon">
        <i class="far fa-comment"></i>
      </span>
      <span class="post-meta-item-text">Disqus: </span>
    
    <a title="disqus" href="/2017/09/07/Extending-nftables/#disqus_thread" itemprop="discussionUrl">
      <span class="post-comments-count disqus-comment-count" data-disqus-identifier="2017/09/07/Extending-nftables/" itemprop="commentCount"></span>
    </a>
  </span>
  
  

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
        <h1 id="Introduction"><a href="#Introduction" class="headerlink" title="Introduction"></a>Introduction</h1><p>I’m recently writing something that uses Linux’s firewall framework to do some non-standard operations packets. Extending the kernel is required for my task but unfortunately documentations about this topic I find online are quite dated. These old documents are mainly for kernel version 2.4 and earlier 2.6.x, in which new matches or targets are registered by calling <code>ipt_register_match</code> and <code>ipt_register_target</code>. The related subsystem of kernel has changed a lot since then, and iptables has been replaced by nftables. Although we can use <code>xt_register_match</code> and <code>xt_register_target</code> instead, I prefer to move to the new nftables framework. Due to the lack of documentation, I have to dig into the source code of Linux kernel to figure out how things works, and this post is the note for that. As Linus Torvalds says in 2008, “Linux is evolution, not intelligent design”, the design and API of nftables might be changing very fast. So I’m not only trying to make a brief review on the design or API of nftables. But also, this post will serve as a guide on how to find the correct way of doing things by reading the kernel source code. The eager reader can go directly to <a href="#summary">the summary section</a>. This post is based on kernel version 4.13, the most recent version when this post is started writing.</p>
<p>Here in this post, we will solve a toy problem: monitor all outgoing TCP traffic from port 80, if it contains the string given by the user, log it. I don’t assume any knowledge in the design or kernel API of nftables, but I do assume the reader has read and understand well <a target="_blank" rel="noopener" href="https://wiki.nftables.org/">the official documents on how to use nftables</a>.</p>
<span id="more"></span>

<h1 id="Starting-point-of-kernel-code"><a href="#Starting-point-of-kernel-code" class="headerlink" title="Starting point of kernel code"></a>Starting point of kernel code</h1><p>The starting point is to find which source file to read. The following command gives a nice overview on nftables in Linux kernel:</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">grep -P <span class="string">&#x27;nftables|nf_tables&#x27;</span> -r .</span><br></pre></td></tr></table></figure>

<p>The output shall be something that looks like:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">.&#x2F;include&#x2F;net&#x2F;netfilter&#x2F;nf_tables_core.h:int nf_tables_core_module_init(void);</span><br><span class="line">.&#x2F;include&#x2F;net&#x2F;netfilter&#x2F;nf_tables_core.h:void nf_tables_core_module_exit(void);</span><br><span class="line">.&#x2F;include&#x2F;net&#x2F;netfilter&#x2F;nf_tables_ipv4.h:#include &lt;net&#x2F;netfilter&#x2F;nf_tables.h&gt;</span><br><span class="line">.&#x2F;include&#x2F;net&#x2F;netfilter&#x2F;nf_tables.h:#include &lt;linux&#x2F;netfilter&#x2F;nf_tables.h&gt;</span><br><span class="line">.&#x2F;include&#x2F;net&#x2F;netfilter&#x2F;nf_tables.h: *  struct nft_verdict - nf_tables verdict</span><br><span class="line">.&#x2F;include&#x2F;net&#x2F;netfilter&#x2F;nf_tables.h: *  @code: nf_tables&#x2F;netfilter verdict code</span><br><span class="line">.&#x2F;include&#x2F;net&#x2F;netfilter&#x2F;nf_tables.h: *  struct nft_regs - nf_tables register set</span><br><span class="line">.&#x2F;include&#x2F;net&#x2F;netfilter&#x2F;nf_tables.h: *  struct nft_ctx - nf_tables rule&#x2F;set context</span><br><span class="line">...........</span><br></pre></td></tr></table></figure>

<p>The files listed in the output will be the files to look at. A good tool to read Linux kernel source code is <a target="_blank" rel="noopener" href="http://elixir.free-electrons.com/linux/v4.13/source">FreeElectrons</a>. We can start by looking at the file names in directory <a target="_blank" rel="noopener" href="http://elixir.free-electrons.com/linux/v4.13/source/include/net/netfilter">include/net/netfilter</a> on its website. We can see nft_masq.h, nft_redir.h, nft_reject.h in that directory. These are all actions in nftables. Following the references of symbols defined in these files will lead us towards sample codes on how to create new actions. Let’s take reject as an example. From its <a target="_blank" rel="noopener" href="http://elixir.free-electrons.com/linux/v4.13/source/include/net/netfilter/nft_reject.h">header</a>, we can find an interesting symbol <code>nft_reject_init</code>. Looking around <a target="_blank" rel="noopener" href="http://elixir.free-electrons.com/linux/v4.13/ident/nft_reject_init">all the definitions and references of that symbol</a>, we are able to find the core code at <a target="_blank" rel="noopener" href="http://elixir.free-electrons.com/linux/v4.13/source/net/ipv4/netfilter/nft_reject_ipv4.c">net/ipv4/netfilter/nft_reject_ipv4.c</a>.  In its core code, <a target="_blank" rel="noopener" href="http://elixir.free-electrons.com/linux/v4.13/source/net/ipv4/netfilter/nft_reject_ipv4.c#L61">L61-L72</a> reads:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> __init <span class="title">nft_reject_ipv4_module_init</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	<span class="keyword">return</span> nft_register_expr(&amp;nft_reject_ipv4_type);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> __exit <span class="title">nft_reject_ipv4_module_exit</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	nft_unregister_expr(&amp;nft_reject_ipv4_type);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">module_init(nft_reject_ipv4_module_init);</span><br><span class="line">module_exit(nft_reject_ipv4_module_exit);</span><br></pre></td></tr></table></figure>
<p>We can immediately know from the above code that we should call <code>nft_register_expr</code> to register an expression and call <code>nft_unregister_expr</code> to unregister.</p>
<p>Now let’s take a look at <a target="_blank" rel="noopener" href="http://elixir.free-electrons.com/linux/v4.13/source/include/net/netfilter/nf_tables.h#L999">the prototype of <code>nft_register_expr</code> in nf_tables.h</a>:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">nft_register_expr</span><span class="params">(struct nft_expr_type *)</span></span>;</span><br></pre></td></tr></table></figure>
<p>It takes one parameter of type <code>struct nft_expr_type *</code>. This struct is also defined in nf_tables.h at <a target="_blank" rel="noopener" href="http://elixir.free-electrons.com/linux/v4.13/source/include/net/netfilter/nf_tables.h#L681">L681</a>.  The usage of <code>nft_register_expr</code> and <code>nft_expr_type</code> can be guessed by reading all the examples. The list of all examples can be found from its reference in <a target="_blank" rel="noopener" href="http://elixir.free-electrons.com/linux/v4.13/ident/nft_register_expr">here</a>. In that list, there is one file that looks very interesting from its file name:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">net&#x2F;netfilter&#x2F;nf_tables_core.c, line 251</span><br></pre></td></tr></table></figure>
<p><a target="_blank" rel="noopener" href="http://elixir.free-electrons.com/linux/v4.13/source/net/netfilter/nf_tables_core.c#L251">Open this link</a>, we can see all these basic expressions:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="class"><span class="keyword">struct</span> <span class="title">nft_expr_type</span> *<span class="title">nft_basic_types</span>[] =</span> &#123;</span><br><span class="line">	&amp;nft_imm_type,</span><br><span class="line">	&amp;nft_cmp_type,</span><br><span class="line">	&amp;nft_lookup_type,</span><br><span class="line">	&amp;nft_bitwise_type,</span><br><span class="line">	&amp;nft_byteorder_type,</span><br><span class="line">	&amp;nft_payload_type,</span><br><span class="line">	&amp;nft_dynset_type,</span><br><span class="line">	&amp;nft_range_type,</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> __init <span class="title">nf_tables_core_module_init</span><span class="params">(<span class="keyword">void</span>)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	<span class="keyword">int</span> err, i;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; ARRAY_SIZE(nft_basic_types); i++) &#123;</span><br><span class="line">		err = nft_register_expr(nft_basic_types[i]);</span><br><span class="line">		<span class="keyword">if</span> (err)</span><br><span class="line">			<span class="keyword">goto</span> err;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">err:</span><br><span class="line">	<span class="keyword">while</span> (i-- &gt; <span class="number">0</span>)</span><br><span class="line">		nft_unregister_expr(nft_basic_types[i]);</span><br><span class="line">	<span class="keyword">return</span> err;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>Now we know what to look at. The next step will be to read these examples to get a feeling on how to write our own expression.</p>
<h1 id="The-usage-of-kernel-API"><a href="#The-usage-of-kernel-API" class="headerlink" title="The usage of kernel API"></a>The usage of kernel API</h1><p>To know the usage of related API, we choose to read the reject operation for the inet family and compare operation as sample code. The source code of reject is located at <a target="_blank" rel="noopener" href="http://elixir.free-electrons.com/linux/v4.13/source/net/netfilter/nft_reject_inet.c">net/netfilter/nft_reject_inet.c</a>. The source code of compare is loacated at <a target="_blank" rel="noopener" href="http://elixir.free-electrons.com/linux/v4.13/source/net/netfilter/nft_cmp.c">net/netfilter/nft_cmp.c</a>. In the case that one expression only correspond to one operation, the usage is shown below by the source code of reject operation at <a target="_blank" rel="noopener" href="http://elixir.free-electrons.com/linux/v4.13/source/net/netfilter/nft_reject_inet.c#L120">L120</a>:<a name="nft_expr_ops_and_nft_expr_type_reject"></a></p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="class"><span class="keyword">struct</span> <span class="title">nft_expr_type</span> <span class="title">nft_reject_inet_type</span>;</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">nft_expr_ops</span> <span class="title">nft_reject_inet_ops</span> =</span> &#123;</span><br><span class="line">	.type		= &amp;nft_reject_inet_type,</span><br><span class="line">	.size		= NFT_EXPR_SIZE(<span class="keyword">sizeof</span>(struct nft_reject)),</span><br><span class="line">	.eval		= nft_reject_inet_eval,</span><br><span class="line">	.init		= nft_reject_inet_init,</span><br><span class="line">	.dump		= nft_reject_inet_dump,</span><br><span class="line">	.validate	= nft_reject_validate,</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">static</span> <span class="class"><span class="keyword">struct</span> <span class="title">nft_expr_type</span> <span class="title">nft_reject_inet_type</span> __<span class="title">read_mostly</span> =</span> &#123;</span><br><span class="line">	.family		= NFPROTO_INET,</span><br><span class="line">	.name		= <span class="string">&quot;reject&quot;</span>,</span><br><span class="line">	.ops		= &amp;nft_reject_inet_ops,</span><br><span class="line">	.policy		= nft_reject_policy,</span><br><span class="line">	.maxattr	= NFTA_REJECT_MAX,</span><br><span class="line">	.owner		= THIS_MODULE,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>From the above code, we know that we should create an instance of both <code>struct nft_expr_ops</code> and <code>struct nft_expr_type</code> and point to each other at <code>nft_expr_ops.type</code> and <code>nft_expr_type.ops</code>.  In the case that one expression correspond to many operations, the usage is shown below by the source code of compare operation:<a name="nft_expr_ops_and_nft_expr_type_cmp"></a></p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">nft_expr_ops</span> <span class="title">nft_cmp_ops</span> =</span> &#123;</span><br><span class="line">	.type		= &amp;nft_cmp_type,</span><br><span class="line">	.size		= NFT_EXPR_SIZE(<span class="keyword">sizeof</span>(struct nft_cmp_expr)),</span><br><span class="line">	.eval		= nft_cmp_eval,</span><br><span class="line">	.init		= nft_cmp_init,</span><br><span class="line">	.dump		= nft_cmp_dump,</span><br><span class="line">&#125;;</span><br><span class="line">...........</span><br><span class="line"><span class="keyword">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">nft_expr_ops</span> <span class="title">nft_cmp_fast_ops</span> =</span> &#123;</span><br><span class="line">	.type		= &amp;nft_cmp_type,</span><br><span class="line">	.size		= NFT_EXPR_SIZE(<span class="keyword">sizeof</span>(struct nft_cmp_fast_expr)),</span><br><span class="line">	.eval		= <span class="literal">NULL</span>,	<span class="comment">/* inlined */</span></span><br><span class="line">	.init		= nft_cmp_fast_init,</span><br><span class="line">	.dump		= nft_cmp_fast_dump,</span><br><span class="line">&#125;;</span><br><span class="line">...........</span><br><span class="line"><span class="keyword">static</span> <span class="keyword">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">nft_expr_ops</span> *</span></span><br><span class="line"><span class="class"><span class="title">nft_cmp_select_ops</span>(<span class="title">const</span> <span class="keyword">struct</span> <span class="title">nft_ctx</span> *<span class="title">ctx</span>, <span class="title">const</span> <span class="keyword">struct</span> <span class="title">nlattr</span> * <span class="title">const</span> <span class="title">tb</span>[])</span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">nft_data_desc</span> <span class="title">desc</span>;</span></span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">nft_data</span> <span class="title">data</span>;</span></span><br><span class="line">	<span class="class"><span class="keyword">enum</span> <span class="title">nft_cmp_ops</span> <span class="title">op</span>;</span></span><br><span class="line">	<span class="keyword">int</span> err;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">if</span> (tb[NFTA_CMP_SREG] == <span class="literal">NULL</span> ||</span><br><span class="line">	    tb[NFTA_CMP_OP] == <span class="literal">NULL</span> ||</span><br><span class="line">	    tb[NFTA_CMP_DATA] == <span class="literal">NULL</span>)</span><br><span class="line">		<span class="keyword">return</span> ERR_PTR(-EINVAL);</span><br><span class="line"></span><br><span class="line">	op = ntohl(nla_get_be32(tb[NFTA_CMP_OP]));</span><br><span class="line">	<span class="keyword">switch</span> (op) &#123;</span><br><span class="line">	<span class="keyword">case</span> NFT_CMP_EQ:</span><br><span class="line">	<span class="keyword">case</span> NFT_CMP_NEQ:</span><br><span class="line">	<span class="keyword">case</span> NFT_CMP_LT:</span><br><span class="line">	<span class="keyword">case</span> NFT_CMP_LTE:</span><br><span class="line">	<span class="keyword">case</span> NFT_CMP_GT:</span><br><span class="line">	<span class="keyword">case</span> NFT_CMP_GTE:</span><br><span class="line">		<span class="keyword">break</span>;</span><br><span class="line">	<span class="keyword">default</span>:</span><br><span class="line">		<span class="keyword">return</span> ERR_PTR(-EINVAL);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	err = nft_data_init(<span class="literal">NULL</span>, &amp;data, <span class="keyword">sizeof</span>(data), &amp;desc,</span><br><span class="line">			    tb[NFTA_CMP_DATA]);</span><br><span class="line">	<span class="keyword">if</span> (err &lt; <span class="number">0</span>)</span><br><span class="line">		<span class="keyword">return</span> ERR_PTR(err);</span><br><span class="line"></span><br><span class="line">	<span class="keyword">if</span> (desc.type != NFT_DATA_VALUE) &#123;</span><br><span class="line">		err = -EINVAL;</span><br><span class="line">		<span class="keyword">goto</span> err1;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">if</span> (desc.len &lt;= <span class="keyword">sizeof</span>(u32) &amp;&amp; op == NFT_CMP_EQ)</span><br><span class="line">		<span class="keyword">return</span> &amp;nft_cmp_fast_ops;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">return</span> &amp;nft_cmp_ops;</span><br><span class="line">err1:</span><br><span class="line">	nft_data_release(&amp;data, desc.type);</span><br><span class="line">	<span class="keyword">return</span> ERR_PTR(-EINVAL);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">nft_expr_type</span> <span class="title">nft_cmp_type</span> __<span class="title">read_mostly</span> =</span> &#123;</span><br><span class="line">	.name		= <span class="string">&quot;cmp&quot;</span>,</span><br><span class="line">	.select_ops	= nft_cmp_select_ops,</span><br><span class="line">	.policy		= nft_cmp_policy,</span><br><span class="line">	.maxattr	= NFTA_CMP_MAX,</span><br><span class="line">	.owner		= THIS_MODULE,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>From this we can see that we should create an instance of <code>struct nft_expr_ops</code> for each operation, and use <code>select_ops</code> to choose dynamically which operation to use.  The <code>select_ops</code> should return the pointer to the operation chosen, or an <code>ERR_PTR</code> in case of error. Now Let’s discuss <code>struct nft_expr_ops</code> and <code>struct nft_expr_type</code> in detail separately.</p>
<h2 id="struct-nft-expr-ops"><a href="#struct-nft-expr-ops" class="headerlink" title="struct nft_expr_ops"></a>struct nft_expr_ops</h2><p>Let’s take a look at <code>struct nft_expr_ops</code> first. It’s definition is at <a target="_blank" rel="noopener" href="http://elixir.free-electrons.com/linux/v4.13/source/include/net/netfilter/nf_tables.h#L722">include/net/netfilter/nf_tables.h#L722</a>:<a name="nft_expr_ops"></a></p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> *	struct nft_expr_ops - nf_tables expression operations</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> *	@eval: Expression evaluation function</span></span><br><span class="line"><span class="comment"> *	@size: full expression size, including private data size</span></span><br><span class="line"><span class="comment"> *	@init: initialization function</span></span><br><span class="line"><span class="comment"> *	@destroy: destruction function</span></span><br><span class="line"><span class="comment"> *	@dump: function to dump parameters</span></span><br><span class="line"><span class="comment"> *	@type: expression type</span></span><br><span class="line"><span class="comment"> *	@validate: validate expression, called during loop detection</span></span><br><span class="line"><span class="comment"> *	@data: extra data to attach to this expression operation</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">nft_expr</span>;</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">nft_expr_ops</span> &#123;</span></span><br><span class="line">	<span class="keyword">void</span>				(*eval)(<span class="keyword">const</span> struct nft_expr *expr,</span><br><span class="line">						struct nft_regs *regs,</span><br><span class="line">						<span class="keyword">const</span> struct nft_pktinfo *pkt);</span><br><span class="line">	<span class="keyword">int</span>				(*clone)(struct nft_expr *dst,</span><br><span class="line">						 <span class="keyword">const</span> struct nft_expr *src);</span><br><span class="line">	<span class="keyword">unsigned</span> <span class="keyword">int</span>			size;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">int</span>				(*init)(<span class="keyword">const</span> struct nft_ctx *ctx,</span><br><span class="line">						<span class="keyword">const</span> struct nft_expr *expr,</span><br><span class="line">						<span class="keyword">const</span> struct nlattr * <span class="keyword">const</span> tb[]);</span><br><span class="line">	<span class="keyword">void</span>				(*destroy)(<span class="keyword">const</span> struct nft_ctx *ctx,</span><br><span class="line">						   <span class="keyword">const</span> struct nft_expr *expr);</span><br><span class="line">	<span class="keyword">int</span>				(*dump)(struct sk_buff *skb,</span><br><span class="line">						<span class="keyword">const</span> struct nft_expr *expr);</span><br><span class="line">	<span class="keyword">int</span>				(*validate)(<span class="keyword">const</span> struct nft_ctx *ctx,</span><br><span class="line">						    <span class="keyword">const</span> struct nft_expr *expr,</span><br><span class="line">						    <span class="keyword">const</span> struct nft_data **data);</span><br><span class="line">	<span class="keyword">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">nft_expr_type</span>	*<span class="title">type</span>;</span></span><br><span class="line">	<span class="keyword">void</span>				*data;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>From the name and comments of these fields, we can see that <code>init</code>, <code>destroy</code>, <code>clone</code> play the role of constructor, destructor, and copy constructor. What to do in these functions is shown in <a href="#nft_expr_ops_and_nft_expr_type_reject">the code above</a>. In that code, <code>init</code> is defined as <code>nft_reject_inet_init</code> and <code>clone</code> and <code>destroy</code> are not defined. The source code for <code>nft_reject_inet_init</code> is located at <a target="_blank" rel="noopener" href="http://elixir.free-electrons.com/linux/v4.13/source/net/netfilter/nft_reject_inet.c#L64">L64</a>:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> <span class="title">nft_reject_inet_init</span><span class="params">(<span class="keyword">const</span> struct nft_ctx *ctx,</span></span></span><br><span class="line"><span class="function"><span class="params">				<span class="keyword">const</span> struct nft_expr *expr,</span></span></span><br><span class="line"><span class="function"><span class="params">				<span class="keyword">const</span> struct nlattr * <span class="keyword">const</span> tb[])</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">nft_reject</span> *<span class="title">priv</span> =</span> nft_expr_priv(expr);</span><br><span class="line">	<span class="keyword">int</span> icmp_code;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">if</span> (tb[NFTA_REJECT_TYPE] == <span class="literal">NULL</span>)</span><br><span class="line">		<span class="keyword">return</span> -EINVAL;</span><br><span class="line"></span><br><span class="line">	priv-&gt;type = ntohl(nla_get_be32(tb[NFTA_REJECT_TYPE]));</span><br><span class="line">	<span class="keyword">switch</span> (priv-&gt;type) &#123;</span><br><span class="line">	<span class="keyword">case</span> NFT_REJECT_ICMP_UNREACH:</span><br><span class="line">	<span class="keyword">case</span> NFT_REJECT_ICMPX_UNREACH:</span><br><span class="line">		<span class="keyword">if</span> (tb[NFTA_REJECT_ICMP_CODE] == <span class="literal">NULL</span>)</span><br><span class="line">			<span class="keyword">return</span> -EINVAL;</span><br><span class="line"></span><br><span class="line">		icmp_code = nla_get_u8(tb[NFTA_REJECT_ICMP_CODE]);</span><br><span class="line">		<span class="keyword">if</span> (priv-&gt;type == NFT_REJECT_ICMPX_UNREACH &amp;&amp;</span><br><span class="line">		    icmp_code &gt; NFT_REJECT_ICMPX_MAX)</span><br><span class="line">			<span class="keyword">return</span> -EINVAL;</span><br><span class="line"></span><br><span class="line">		priv-&gt;icmp_code = icmp_code;</span><br><span class="line">		<span class="keyword">break</span>;</span><br><span class="line">	<span class="keyword">case</span> NFT_REJECT_TCP_RST:</span><br><span class="line">		<span class="keyword">break</span>;</span><br><span class="line">	<span class="keyword">default</span>:</span><br><span class="line">		<span class="keyword">return</span> -EINVAL;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>By reading this function and looking into all other functions called by this function, we can see that the following things will happen: The kernel will allocate memory for an instance of <code>struct nft_reject</code>, which is the struct that stores operation specific data, at <code>expr-&gt;data</code>. In order for the kernel to know the size of memory to allocate for <code>struct nft_reject</code>, its size is passed to <code>nft_expr_ops.size</code> as shown in the 4th line at <a href="#nft_expr_ops_and_nft_expr_type_reject">the code snippet above</a>:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">.size = NFT_EXPR_SIZE(<span class="keyword">sizeof</span>(struct nft_reject))</span><br></pre></td></tr></table></figure>
<p>The <code>init</code> function is responsible to initialize the fields of this instance by reading attributes from <a target="_blank" rel="noopener" href="https://en.wikipedia.org/wiki/Netlink">netlink</a> by calling functions like <code>nla_get_&lt;type&gt;</code>. Data from netlink is stored at the argument <code>tb</code>. In case of error, the <code>init</code> function should return a negative number, otherwise <code>0</code> should be returned. <a name="question_netlink"></a>Up to now, we are not sure how to let netlink know what attributes are expected and what are the length of these attributes yet, but don’t worry, things will become clear as we keep reading. Let’s for now just forget about this problem.</p>
<p>Now let’s take a look at the <code>dump</code> field, it is implemented by <code>nft_reject_inet_dump</code> for reject operation. The code is located at <a target="_blank" rel="noopener" href="http://elixir.free-electrons.com/linux/v4.13/source/net/netfilter/nft_reject_inet.c#L96">L96</a>:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> <span class="title">nft_reject_inet_dump</span><span class="params">(struct sk_buff *skb,</span></span></span><br><span class="line"><span class="function"><span class="params">				<span class="keyword">const</span> struct nft_expr *expr)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	<span class="keyword">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">nft_reject</span> *<span class="title">priv</span> =</span> nft_expr_priv(expr);</span><br><span class="line"></span><br><span class="line">	<span class="keyword">if</span> (nla_put_be32(skb, NFTA_REJECT_TYPE, htonl(priv-&gt;type)))</span><br><span class="line">		<span class="keyword">goto</span> nla_put_failure;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">switch</span> (priv-&gt;type) &#123;</span><br><span class="line">	<span class="keyword">case</span> NFT_REJECT_ICMP_UNREACH:</span><br><span class="line">	<span class="keyword">case</span> NFT_REJECT_ICMPX_UNREACH:</span><br><span class="line">		<span class="keyword">if</span> (nla_put_u8(skb, NFTA_REJECT_ICMP_CODE, priv-&gt;icmp_code))</span><br><span class="line">			<span class="keyword">goto</span> nla_put_failure;</span><br><span class="line">		<span class="keyword">break</span>;</span><br><span class="line">	<span class="keyword">default</span>:</span><br><span class="line">		<span class="keyword">break</span>;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">nla_put_failure:</span><br><span class="line">	<span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>We can see that this operation send back the parameters to netlink using functions like <code>nla_put_&lt;type&gt;</code>. In case of success, <code>0</code> should be returned, otherwise it should return a negative number.</p>
<p>The function that evaluate the evaluation correspond to the field <code>eval</code>. We can think of there are two types of expressions: those that match some conditions, and those that do something, such as drop, reject, accept, dnat, etc., to the packets. For these two types, the <code>eval</code> should be slightly different. Here we use the source code of both compare and reject as example. In reject, it is implemented as <code>nft_reject_inet_eval</code>. The source code is located at <a target="_blank" rel="noopener" href="http://elixir.free-electrons.com/linux/v4.13/source/net/netfilter/nft_reject_inet.c#L20">L20</a>:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">nft_reject_inet_eval</span><span class="params">(<span class="keyword">const</span> struct nft_expr *expr,</span></span></span><br><span class="line"><span class="function"><span class="params">				 struct nft_regs *regs,</span></span></span><br><span class="line"><span class="function"><span class="params">				 <span class="keyword">const</span> struct nft_pktinfo *pkt)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">nft_reject</span> *<span class="title">priv</span> =</span> nft_expr_priv(expr);</span><br><span class="line"></span><br><span class="line">	<span class="keyword">switch</span> (nft_pf(pkt)) &#123;</span><br><span class="line">	<span class="keyword">case</span> NFPROTO_IPV4:</span><br><span class="line">		<span class="keyword">switch</span> (priv-&gt;type) &#123;</span><br><span class="line">		<span class="keyword">case</span> NFT_REJECT_ICMP_UNREACH:</span><br><span class="line">			nf_send_unreach(pkt-&gt;skb, priv-&gt;icmp_code,</span><br><span class="line">					nft_hook(pkt));</span><br><span class="line">			<span class="keyword">break</span>;</span><br><span class="line">		<span class="keyword">case</span> NFT_REJECT_TCP_RST:</span><br><span class="line">			nf_send_reset(nft_net(pkt), pkt-&gt;skb, nft_hook(pkt));</span><br><span class="line">			<span class="keyword">break</span>;</span><br><span class="line">		<span class="keyword">case</span> NFT_REJECT_ICMPX_UNREACH:</span><br><span class="line">			nf_send_unreach(pkt-&gt;skb,</span><br><span class="line">					nft_reject_icmp_code(priv-&gt;icmp_code),</span><br><span class="line">					nft_hook(pkt));</span><br><span class="line">			<span class="keyword">break</span>;</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">break</span>;</span><br><span class="line">	<span class="keyword">case</span> NFPROTO_IPV6:</span><br><span class="line">		<span class="keyword">switch</span> (priv-&gt;type) &#123;</span><br><span class="line">		<span class="keyword">case</span> NFT_REJECT_ICMP_UNREACH:</span><br><span class="line">			nf_send_unreach6(nft_net(pkt), pkt-&gt;skb,</span><br><span class="line">					 priv-&gt;icmp_code, nft_hook(pkt));</span><br><span class="line">			<span class="keyword">break</span>;</span><br><span class="line">		<span class="keyword">case</span> NFT_REJECT_TCP_RST:</span><br><span class="line">			nf_send_reset6(nft_net(pkt), pkt-&gt;skb, nft_hook(pkt));</span><br><span class="line">			<span class="keyword">break</span>;</span><br><span class="line">		<span class="keyword">case</span> NFT_REJECT_ICMPX_UNREACH:</span><br><span class="line">			nf_send_unreach6(nft_net(pkt), pkt-&gt;skb,</span><br><span class="line">					 nft_reject_icmpv6_code(priv-&gt;icmp_code),</span><br><span class="line">					 nft_hook(pkt));</span><br><span class="line">			<span class="keyword">break</span>;</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">break</span>;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	regs-&gt;verdict.code = NF_DROP;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>In the compare operation, it is implemented as <code>nft_cmp_eval</code>. The source code is located at <a target="_blank" rel="noopener" href="http://elixir.free-electrons.com/linux/v4.13/source/net/netfilter/nft_cmp.c#L27">L27</a>:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">nft_cmp_eval</span><span class="params">(<span class="keyword">const</span> struct nft_expr *expr,</span></span></span><br><span class="line"><span class="function"><span class="params">			 struct nft_regs *regs,</span></span></span><br><span class="line"><span class="function"><span class="params">			 <span class="keyword">const</span> struct nft_pktinfo *pkt)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	<span class="keyword">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">nft_cmp_expr</span> *<span class="title">priv</span> =</span> nft_expr_priv(expr);</span><br><span class="line">	<span class="keyword">int</span> d;</span><br><span class="line"></span><br><span class="line">	d = <span class="built_in">memcmp</span>(&amp;regs-&gt;data[priv-&gt;sreg], &amp;priv-&gt;data, priv-&gt;len);</span><br><span class="line">	<span class="keyword">switch</span> (priv-&gt;op) &#123;</span><br><span class="line">	<span class="keyword">case</span> NFT_CMP_EQ:</span><br><span class="line">		<span class="keyword">if</span> (d != <span class="number">0</span>)</span><br><span class="line">			<span class="keyword">goto</span> mismatch;</span><br><span class="line">		<span class="keyword">break</span>;</span><br><span class="line">	<span class="keyword">case</span> NFT_CMP_NEQ:</span><br><span class="line">		<span class="keyword">if</span> (d == <span class="number">0</span>)</span><br><span class="line">			<span class="keyword">goto</span> mismatch;</span><br><span class="line">		<span class="keyword">break</span>;</span><br><span class="line">	<span class="keyword">case</span> NFT_CMP_LT:</span><br><span class="line">		<span class="keyword">if</span> (d == <span class="number">0</span>)</span><br><span class="line">			<span class="keyword">goto</span> mismatch;</span><br><span class="line">	<span class="keyword">case</span> NFT_CMP_LTE:</span><br><span class="line">		<span class="keyword">if</span> (d &gt; <span class="number">0</span>)</span><br><span class="line">			<span class="keyword">goto</span> mismatch;</span><br><span class="line">		<span class="keyword">break</span>;</span><br><span class="line">	<span class="keyword">case</span> NFT_CMP_GT:</span><br><span class="line">		<span class="keyword">if</span> (d == <span class="number">0</span>)</span><br><span class="line">			<span class="keyword">goto</span> mismatch;</span><br><span class="line">	<span class="keyword">case</span> NFT_CMP_GTE:</span><br><span class="line">		<span class="keyword">if</span> (d &lt; <span class="number">0</span>)</span><br><span class="line">			<span class="keyword">goto</span> mismatch;</span><br><span class="line">		<span class="keyword">break</span>;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">return</span>;</span><br><span class="line"></span><br><span class="line">mismatch:</span><br><span class="line">	regs-&gt;verdict.code = NFT_BREAK;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>From these two functions, we can see that this function tells the kernel to do something by setting <code>regs-&gt;verdict.code</code> or to continue to the next expression by not changing <code>regs-&gt;verdict.code</code>. For actions, the value of <code>regs-&gt;verdict.code</code> should be set to one of the following as shown in <a target="_blank" rel="noopener" href="http://elixir.free-electrons.com/linux/v4.13/source/include/uapi/linux/netfilter.h#L9">include/uapi/linux/netfilter.h#L9</a>:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Responses from hook functions. */</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> NF_DROP 0</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> NF_ACCEPT 1</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> NF_STOLEN 2</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> NF_QUEUE 3</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> NF_REPEAT 4</span></span><br></pre></td></tr></table></figure>
<p>For matches, it should be a value in <code>enum nft_verdicts</code>, which is listed at <a target="_blank" rel="noopener" href="http://elixir.free-electrons.com/linux/v4.13/source/include/uapi/linux/netfilter/nf_tables.h#L49">include/uapi/linux/netfilter/nf_tables.h#L49</a>:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * enum nft_verdicts - nf_tables internal verdicts</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * @NFT_CONTINUE: continue evaluation of the current rule</span></span><br><span class="line"><span class="comment"> * @NFT_BREAK: terminate evaluation of the current rule</span></span><br><span class="line"><span class="comment"> * @NFT_JUMP: push the current chain on the jump stack and jump to a chain</span></span><br><span class="line"><span class="comment"> * @NFT_GOTO: jump to a chain without pushing the current chain on the jump stack</span></span><br><span class="line"><span class="comment"> * @NFT_RETURN: return to the topmost chain on the jump stack</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * The nf_tables verdicts share their numeric space with the netfilter verdicts.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">enum</span> <span class="title">nft_verdicts</span> &#123;</span></span><br><span class="line">	NFT_CONTINUE	= <span class="number">-1</span>,</span><br><span class="line">	NFT_BREAK	= <span class="number">-2</span>,</span><br><span class="line">	NFT_JUMP	= <span class="number">-3</span>,</span><br><span class="line">	NFT_GOTO	= <span class="number">-4</span>,</span><br><span class="line">	NFT_RETURN	= <span class="number">-5</span>,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<p>The field <code>validate</code> is used to check the validation of operation, for example: masquerade is only available at hook point <code>POSTROUTING</code>, reject is only available at hook point <code>LOCAL INPUT</code>, <code>LOCAL_OUTPUT</code> and <code>FORWARD</code>, etc. This can be shown at the source code of at <a target="_blank" rel="noopener" href="http://elixir.free-electrons.com/linux/v4.13/source/net/netfilter/nft_reject.c#L29">net/netfilter/nft_reject.c#L29</a>:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">nft_reject_validate</span><span class="params">(<span class="keyword">const</span> struct nft_ctx *ctx,</span></span></span><br><span class="line"><span class="function"><span class="params">			<span class="keyword">const</span> struct nft_expr *expr,</span></span></span><br><span class="line"><span class="function"><span class="params">			<span class="keyword">const</span> struct nft_data **data)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	<span class="keyword">return</span> nft_chain_validate_hooks(ctx-&gt;chain,</span><br><span class="line">					(<span class="number">1</span> &lt;&lt; NF_INET_LOCAL_IN) |</span><br><span class="line">					(<span class="number">1</span> &lt;&lt; NF_INET_FORWARD) |</span><br><span class="line">					(<span class="number">1</span> &lt;&lt; NF_INET_LOCAL_OUT));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>The function <code>nft_chain_validate_hooks</code> is used to validate the hook point. There are other helper functions to validate different things, the list of these functions can be obtained by searching the string “validate” at <a target="_blank" rel="noopener" href="http://elixir.free-electrons.com/linux/v4.13/source/include/net/netfilter/nf_tables.h">include/net/netfilter/nf_tables.h</a>.</p>
<h2 id="struct-nft-expr-type"><a href="#struct-nft-expr-type" class="headerlink" title="struct nft_expr_type"></a>struct nft_expr_type</h2><p>The definition of <code>nft_expr_type</code> is at <a target="_blank" rel="noopener" href="http://elixir.free-electrons.com/linux/v4.13/source/include/net/netfilter/nf_tables.h#L681">include/net/netfilter/nf_tables.h#L681</a>:<a name="nft_expr_type"></a><br><a name="nft_expr_type"></a>```C<br>/**</p>
<ul>
<li>   struct nft_expr_type - nf_tables expression type</li>
<li></li>
<li>   @select_ops: function to select nft_expr_ops</li>
<li>   @ops: default ops, used when no select_ops functions is present</li>
<li>   @list: used internally</li>
<li>   @name: Identifier</li>
<li>   @owner: module reference</li>
<li>   @policy: netlink attribute policy</li>
<li>   @maxattr: highest netlink attribute number</li>
<li>   @family: address family for AF-specific types</li>
<li>   @flags: expression type flags</li>
<li>/<br>struct nft_expr_type {<br>  const struct nft_expr_ops    *(*select_ops)(const struct nft_ctx *,<pre><code>                         const struct nlattr * const tb[]);
</code></pre>
  const struct nft_expr_ops    *ops;<br>  struct list_head        list;<br>  const char            *name;<br>  struct module            *owner;<br>  const struct nla_policy        *policy;<br>  unsigned int            maxattr;<br>  u8                family;<br>  u8                flags;<br>};<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">The field &#96;ops&#96; and &#96;select_ops&#96; is already discussed; the field &#96;list&#96; is internally, so we should not worry about it here; the field &#96;name&#96; is the name of the expression; the field &#96;owner&#96; should be set to the pointer towards the current module. These are all trivial fields. Now let&#39;s take a look at the &#96;policy&#96; and &#96;maxattr&#96; field. The related code at [the definition of &#96;nft_reject_inet_type&#96;](#nft_expr_ops_and_nft_expr_type_reject) is:</span><br><span class="line">&#96;&#96;&#96;C</span><br><span class="line">.policy &#x3D; nft_reject_policy,</span><br><span class="line">.maxattr &#x3D; NFTA_REJECT_MAX,</span><br></pre></td></tr></table></figure>
The array <code>nft_reject_policy</code> is defined at <a target="_blank" rel="noopener" href="http://elixir.free-electrons.com/linux/v4.13/source/net/netfilter/nft_reject.c#L23">L23</a>:<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">nla_policy</span> <span class="title">nft_reject_policy</span>[<span class="title">NFTA_REJECT_MAX</span> + 1] =</span> &#123;</span><br><span class="line">	[NFTA_REJECT_TYPE]		= &#123; .type = NLA_U32 &#125;,</span><br><span class="line">	[NFTA_REJECT_ICMP_CODE]		= &#123; .type = NLA_U8 &#125;,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
The two array index above, <code>NFTA_REJECT_TYPE</code> and <code>NFTA_REJECT_ICMP_CODE</code>, belongs to an enum named <code>nft_reject_attributes</code>. And the definition of <code>NFTA_REJECT_MAX</code> and <code>nft_reject_attributes</code> is located at <a target="_blank" rel="noopener" href="http://elixir.free-electrons.com/linux/v4.13/source/include/uapi/linux/netfilter/nf_tables.h#L1089">include/uapi/linux/netfilter/nf_tables.h#L1089</a>:<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * enum nft_reject_attributes - nf_tables reject expression netlink attributes</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * @NFTA_REJECT_TYPE: packet type to use (NLA_U32: nft_reject_types)</span></span><br><span class="line"><span class="comment"> * @NFTA_REJECT_ICMP_CODE: ICMP code to use (NLA_U8)</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">enum</span> <span class="title">nft_reject_attributes</span> &#123;</span></span><br><span class="line">	NFTA_REJECT_UNSPEC,</span><br><span class="line">	NFTA_REJECT_TYPE,</span><br><span class="line">	NFTA_REJECT_ICMP_CODE,</span><br><span class="line">	__NFTA_REJECT_MAX</span><br><span class="line">&#125;;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> NFTA_REJECT_MAX		(__NFTA_REJECT_MAX - 1)</span></span><br></pre></td></tr></table></figure>
Recall that we raised a question <a href="#question_netlink">before</a> on how does the kernel knows what are the attributes expected by the expression. The <code>policy</code> field is exactly the answer to this question. Let’s now dig deeper and read the source code of netlink starting at <a target="_blank" rel="noopener" href="http://elixir.free-electrons.com/linux/v4.13/source/include/net/netlink.h#L9">include/net/netlink.h#L9</a>:<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* ========================================================================</span></span><br><span class="line"><span class="comment"> *         Netlink Messages and Attributes Interface (As Seen On TV)</span></span><br><span class="line"><span class="comment"> * ------------------------------------------------------------------------</span></span><br><span class="line"><span class="comment"> *                          Messages Interface</span></span><br><span class="line"><span class="comment"> * ------------------------------------------------------------------------</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Message Format:</span></span><br><span class="line"><span class="comment"> *    &lt;--- nlmsg_total_size(payload)  ---&gt;</span></span><br><span class="line"><span class="comment"> *    &lt;-- nlmsg_msg_size(payload) -&gt;</span></span><br><span class="line"><span class="comment"> *   +----------+- - -+-------------+- - -+-------- - -</span></span><br><span class="line"><span class="comment"> *   | nlmsghdr | Pad |   Payload   | Pad | nlmsghdr</span></span><br><span class="line"><span class="comment"> *   +----------+- - -+-------------+- - -+-------- - -</span></span><br><span class="line"><span class="comment"> *   nlmsg_data(nlh)---^                   ^</span></span><br><span class="line"><span class="comment"> *   nlmsg_next(nlh)-----------------------+</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Payload Format:</span></span><br><span class="line"><span class="comment"> *    &lt;---------------------- nlmsg_len(nlh) ---------------------&gt;</span></span><br><span class="line"><span class="comment"> *    &lt;------ hdrlen ------&gt;       &lt;- nlmsg_attrlen(nlh, hdrlen) -&gt;</span></span><br><span class="line"><span class="comment"> *   +----------------------+- - -+--------------------------------+</span></span><br><span class="line"><span class="comment"> *   |     Family Header    | Pad |           Attributes           |</span></span><br><span class="line"><span class="comment"> *   +----------------------+- - -+--------------------------------+</span></span><br><span class="line"><span class="comment"> *   nlmsg_attrdata(nlh, hdrlen)---^</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Data Structures:</span></span><br><span class="line"><span class="comment"> *   struct nlmsghdr			netlink message header</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Message Construction:</span></span><br><span class="line"><span class="comment"> *   nlmsg_new()			create a new netlink message</span></span><br><span class="line"><span class="comment"> *   nlmsg_put()			add a netlink message to an skb</span></span><br><span class="line"><span class="comment"> *   nlmsg_put_answer()			callback based nlmsg_put()</span></span><br><span class="line"><span class="comment"> *   nlmsg_end()			finalize netlink message</span></span><br><span class="line"><span class="comment"> *   nlmsg_get_pos()			return current position in message</span></span><br><span class="line"><span class="comment"> *   nlmsg_trim()			trim part of message</span></span><br><span class="line"><span class="comment"> *   nlmsg_cancel()			cancel message construction</span></span><br><span class="line"><span class="comment"> *   nlmsg_free()			free a netlink message</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Message Sending:</span></span><br><span class="line"><span class="comment"> *   nlmsg_multicast()			multicast message to several groups</span></span><br><span class="line"><span class="comment"> *   nlmsg_unicast()			unicast a message to a single socket</span></span><br><span class="line"><span class="comment"> *   nlmsg_notify()			send notification message</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Message Length Calculations:</span></span><br><span class="line"><span class="comment"> *   nlmsg_msg_size(payload)		length of message w/o padding</span></span><br><span class="line"><span class="comment"> *   nlmsg_total_size(payload)		length of message w/ padding</span></span><br><span class="line"><span class="comment"> *   nlmsg_padlen(payload)		length of padding at tail</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Message Payload Access:</span></span><br><span class="line"><span class="comment"> *   nlmsg_data(nlh)			head of message payload</span></span><br><span class="line"><span class="comment"> *   nlmsg_len(nlh)			length of message payload</span></span><br><span class="line"><span class="comment"> *   nlmsg_attrdata(nlh, hdrlen)	head of attributes data</span></span><br><span class="line"><span class="comment"> *   nlmsg_attrlen(nlh, hdrlen)		length of attributes data</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Message Parsing:</span></span><br><span class="line"><span class="comment"> *   nlmsg_ok(nlh, remaining)		does nlh fit into remaining bytes?</span></span><br><span class="line"><span class="comment"> *   nlmsg_next(nlh, remaining)		get next netlink message</span></span><br><span class="line"><span class="comment"> *   nlmsg_parse()			parse attributes of a message</span></span><br><span class="line"><span class="comment"> *   nlmsg_find_attr()			find an attribute in a message</span></span><br><span class="line"><span class="comment"> *   nlmsg_for_each_msg()		loop over all messages</span></span><br><span class="line"><span class="comment"> *   nlmsg_validate()			validate netlink message incl. attrs</span></span><br><span class="line"><span class="comment"> *   nlmsg_for_each_attr()		loop over all attributes</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Misc:</span></span><br><span class="line"><span class="comment"> *   nlmsg_report()			report back to application?</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * ------------------------------------------------------------------------</span></span><br><span class="line"><span class="comment"> *                          Attributes Interface</span></span><br><span class="line"><span class="comment"> * ------------------------------------------------------------------------</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Attribute Format:</span></span><br><span class="line"><span class="comment"> *    &lt;------- nla_total_size(payload) -------&gt;</span></span><br><span class="line"><span class="comment"> *    &lt;---- nla_attr_size(payload) -----&gt;</span></span><br><span class="line"><span class="comment"> *   +----------+- - -+- - - - - - - - - +- - -+-------- - -</span></span><br><span class="line"><span class="comment"> *   |  Header  | Pad |     Payload      | Pad |  Header</span></span><br><span class="line"><span class="comment"> *   +----------+- - -+- - - - - - - - - +- - -+-------- - -</span></span><br><span class="line"><span class="comment"> *                     &lt;- nla_len(nla) -&gt;      ^</span></span><br><span class="line"><span class="comment"> *   nla_data(nla)----^                        |</span></span><br><span class="line"><span class="comment"> *   nla_next(nla)-----------------------------&#x27;</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Data Structures:</span></span><br><span class="line"><span class="comment"> *   struct nlattr			netlink attribute header</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Attribute Construction:</span></span><br><span class="line"><span class="comment"> *   nla_reserve(skb, type, len)	reserve room for an attribute</span></span><br><span class="line"><span class="comment"> *   nla_reserve_nohdr(skb, len)	reserve room for an attribute w/o hdr</span></span><br><span class="line"><span class="comment"> *   nla_put(skb, type, len, data)	add attribute to skb</span></span><br><span class="line"><span class="comment"> *   nla_put_nohdr(skb, len, data)	add attribute w/o hdr</span></span><br><span class="line"><span class="comment"> *   nla_append(skb, len, data)		append data to skb</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Attribute Construction for Basic Types:</span></span><br><span class="line"><span class="comment"> *   nla_put_u8(skb, type, value)	add u8 attribute to skb</span></span><br><span class="line"><span class="comment"> *   nla_put_u16(skb, type, value)	add u16 attribute to skb</span></span><br><span class="line"><span class="comment"> *   nla_put_u32(skb, type, value)	add u32 attribute to skb</span></span><br><span class="line"><span class="comment"> *   nla_put_u64_64bit(skb, type,</span></span><br><span class="line"><span class="comment"> *                     value, padattr)	add u64 attribute to skb</span></span><br><span class="line"><span class="comment"> *   nla_put_s8(skb, type, value)	add s8 attribute to skb</span></span><br><span class="line"><span class="comment"> *   nla_put_s16(skb, type, value)	add s16 attribute to skb</span></span><br><span class="line"><span class="comment"> *   nla_put_s32(skb, type, value)	add s32 attribute to skb</span></span><br><span class="line"><span class="comment"> *   nla_put_s64(skb, type, value,</span></span><br><span class="line"><span class="comment"> *               padattr)		add s64 attribute to skb</span></span><br><span class="line"><span class="comment"> *   nla_put_string(skb, type, str)	add string attribute to skb</span></span><br><span class="line"><span class="comment"> *   nla_put_flag(skb, type)		add flag attribute to skb</span></span><br><span class="line"><span class="comment"> *   nla_put_msecs(skb, type, jiffies,</span></span><br><span class="line"><span class="comment"> *                 padattr)		add msecs attribute to skb</span></span><br><span class="line"><span class="comment"> *   nla_put_in_addr(skb, type, addr)	add IPv4 address attribute to skb</span></span><br><span class="line"><span class="comment"> *   nla_put_in6_addr(skb, type, addr)	add IPv6 address attribute to skb</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Nested Attributes Construction:</span></span><br><span class="line"><span class="comment"> *   nla_nest_start(skb, type)		start a nested attribute</span></span><br><span class="line"><span class="comment"> *   nla_nest_end(skb, nla)		finalize a nested attribute</span></span><br><span class="line"><span class="comment"> *   nla_nest_cancel(skb, nla)		cancel nested attribute construction</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Attribute Length Calculations:</span></span><br><span class="line"><span class="comment"> *   nla_attr_size(payload)		length of attribute w/o padding</span></span><br><span class="line"><span class="comment"> *   nla_total_size(payload)		length of attribute w/ padding</span></span><br><span class="line"><span class="comment"> *   nla_padlen(payload)		length of padding</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Attribute Payload Access:</span></span><br><span class="line"><span class="comment"> *   nla_data(nla)			head of attribute payload</span></span><br><span class="line"><span class="comment"> *   nla_len(nla)			length of attribute payload</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Attribute Payload Access for Basic Types:</span></span><br><span class="line"><span class="comment"> *   nla_get_u8(nla)			get payload for a u8 attribute</span></span><br><span class="line"><span class="comment"> *   nla_get_u16(nla)			get payload for a u16 attribute</span></span><br><span class="line"><span class="comment"> *   nla_get_u32(nla)			get payload for a u32 attribute</span></span><br><span class="line"><span class="comment"> *   nla_get_u64(nla)			get payload for a u64 attribute</span></span><br><span class="line"><span class="comment"> *   nla_get_s8(nla)			get payload for a s8 attribute</span></span><br><span class="line"><span class="comment"> *   nla_get_s16(nla)			get payload for a s16 attribute</span></span><br><span class="line"><span class="comment"> *   nla_get_s32(nla)			get payload for a s32 attribute</span></span><br><span class="line"><span class="comment"> *   nla_get_s64(nla)			get payload for a s64 attribute</span></span><br><span class="line"><span class="comment"> *   nla_get_flag(nla)			return 1 if flag is true</span></span><br><span class="line"><span class="comment"> *   nla_get_msecs(nla)			get payload for a msecs attribute</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Attribute Misc:</span></span><br><span class="line"><span class="comment"> *   nla_memcpy(dest, nla, count)	copy attribute into memory</span></span><br><span class="line"><span class="comment"> *   nla_memcmp(nla, data, size)	compare attribute with memory area</span></span><br><span class="line"><span class="comment"> *   nla_strlcpy(dst, nla, size)	copy attribute to a sized string</span></span><br><span class="line"><span class="comment"> *   nla_strcmp(nla, str)		compare attribute with string</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Attribute Parsing:</span></span><br><span class="line"><span class="comment"> *   nla_ok(nla, remaining)		does nla fit into remaining bytes?</span></span><br><span class="line"><span class="comment"> *   nla_next(nla, remaining)		get next netlink attribute</span></span><br><span class="line"><span class="comment"> *   nla_validate()			validate a stream of attributes</span></span><br><span class="line"><span class="comment"> *   nla_validate_nested()		validate a stream of nested attributes</span></span><br><span class="line"><span class="comment"> *   nla_find()				find attribute in stream of attributes</span></span><br><span class="line"><span class="comment"> *   nla_find_nested()			find attribute in nested attributes</span></span><br><span class="line"><span class="comment"> *   nla_parse()			parse and validate stream of attrs</span></span><br><span class="line"><span class="comment"> *   nla_parse_nested()			parse nested attribuets</span></span><br><span class="line"><span class="comment"> *   nla_for_each_attr()		loop over all attributes</span></span><br><span class="line"><span class="comment"> *   nla_for_each_nested()		loop over the nested attributes</span></span><br><span class="line"><span class="comment"> *=========================================================================</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment">  * Standard attribute types to specify validation policy</span></span><br><span class="line"><span class="comment">  */</span></span><br><span class="line"><span class="class"><span class="keyword">enum</span> &#123;</span></span><br><span class="line">	NLA_UNSPEC,</span><br><span class="line">	NLA_U8,</span><br><span class="line">	NLA_U16,</span><br><span class="line">	NLA_U32,</span><br><span class="line">	NLA_U64,</span><br><span class="line">	NLA_STRING,</span><br><span class="line">	NLA_FLAG,</span><br><span class="line">	NLA_MSECS,</span><br><span class="line">	NLA_NESTED,</span><br><span class="line">	NLA_NESTED_COMPAT,</span><br><span class="line">	NLA_NUL_STRING,</span><br><span class="line">	NLA_BINARY,</span><br><span class="line">	NLA_S8,</span><br><span class="line">	NLA_S16,</span><br><span class="line">	NLA_S32,</span><br><span class="line">	NLA_S64,</span><br><span class="line">	__NLA_TYPE_MAX,</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> NLA_TYPE_MAX (__NLA_TYPE_MAX - 1)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * struct nla_policy - attribute validation policy</span></span><br><span class="line"><span class="comment"> * @type: Type of attribute or NLA_UNSPEC</span></span><br><span class="line"><span class="comment"> * @len: Type specific length of payload</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Policies are defined as arrays of this struct, the array must be</span></span><br><span class="line"><span class="comment"> * accessible by attribute type up to the highest identifier to be expected.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Meaning of `len&#x27; field:</span></span><br><span class="line"><span class="comment"> *    NLA_STRING           Maximum length of string</span></span><br><span class="line"><span class="comment"> *    NLA_NUL_STRING       Maximum length of string (excluding NUL)</span></span><br><span class="line"><span class="comment"> *    NLA_FLAG             Unused</span></span><br><span class="line"><span class="comment"> *    NLA_BINARY           Maximum length of attribute payload</span></span><br><span class="line"><span class="comment"> *    NLA_NESTED           Don&#x27;t use `len&#x27; field -- length verification is</span></span><br><span class="line"><span class="comment"> *                         done by checking len of nested header (or empty)</span></span><br><span class="line"><span class="comment"> *    NLA_NESTED_COMPAT    Minimum length of structure payload</span></span><br><span class="line"><span class="comment"> *    NLA_U8, NLA_U16,</span></span><br><span class="line"><span class="comment"> *    NLA_U32, NLA_U64,</span></span><br><span class="line"><span class="comment"> *    NLA_S8, NLA_S16,</span></span><br><span class="line"><span class="comment"> *    NLA_S32, NLA_S64,</span></span><br><span class="line"><span class="comment"> *    NLA_MSECS            Leaving the length field zero will verify the</span></span><br><span class="line"><span class="comment"> *                         given type fits, using it verifies minimum length</span></span><br><span class="line"><span class="comment"> *                         just like &quot;All other&quot;</span></span><br><span class="line"><span class="comment"> *    All other            Minimum length of attribute payload</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Example:</span></span><br><span class="line"><span class="comment"> * static const struct nla_policy my_policy[ATTR_MAX+1] = &#123;</span></span><br><span class="line"><span class="comment"> * 	[ATTR_FOO] = &#123; .type = NLA_U16 &#125;,</span></span><br><span class="line"><span class="comment"> *	[ATTR_BAR] = &#123; .type = NLA_STRING, .len = BARSIZ &#125;,</span></span><br><span class="line"><span class="comment"> *	[ATTR_BAZ] = &#123; .len = sizeof(struct mystruct) &#125;,</span></span><br><span class="line"><span class="comment"> * &#125;;</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">nla_policy</span> &#123;</span></span><br><span class="line">	u16		type;</span><br><span class="line">	u16		len;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
The comments explains itself very well. The source code of attributes of different expressions are all defined at <a target="_blank" rel="noopener" href="http://elixir.free-electrons.com/linux/v4.13/source/include/uapi/linux/netfilter/nf_tables.h">include/uapi/linux/netfilter/nf_tables.h</a>. To get a feeling on how to write an array like this, just search the string “attributes” in this file. All definition of attributes should begin with an <code>UNSPEC</code> to leave space for internal usage.</li>
</ul>
<p>The field <code>family</code> is the address family of your expression. Possible values can be found at <a target="_blank" rel="noopener" href="http://elixir.free-electrons.com/linux/v4.13/source/include/uapi/linux/netfilter.h#L59">include/uapi/linux/netfilter.h#L59</a>:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">enum</span> &#123;</span></span><br><span class="line">	NFPROTO_UNSPEC =  <span class="number">0</span>,</span><br><span class="line">	NFPROTO_INET   =  <span class="number">1</span>,</span><br><span class="line">	NFPROTO_IPV4   =  <span class="number">2</span>,</span><br><span class="line">	NFPROTO_ARP    =  <span class="number">3</span>,</span><br><span class="line">	NFPROTO_NETDEV =  <span class="number">5</span>,</span><br><span class="line">	NFPROTO_BRIDGE =  <span class="number">7</span>,</span><br><span class="line">	NFPROTO_IPV6   = <span class="number">10</span>,</span><br><span class="line">	NFPROTO_DECNET = <span class="number">12</span>,</span><br><span class="line">	NFPROTO_NUMPROTO,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<p>The field <code>flags</code> are used to denote expression types. Currently, only one flag is available, that is if an expression is stateful. See <a target="_blank" rel="noopener" href="http://elixir.free-electrons.com/linux/v4.13/source/include/net/netfilter/nf_tables.h#L707">include/net/netfilter/nf_tables.h#L707</a>:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">define</span> NFT_EXPR_STATEFUL		0x1</span></span><br></pre></td></tr></table></figure>

<h1 id="Summary-on-kernel-codes"><a href="#Summary-on-kernel-codes" class="headerlink" title="Summary on kernel codes"></a><a name="summary"></a>Summary on kernel codes</h1><p>Create an instance of <code>struct nft_expr_ops</code> for each operation of this expression. Implements its fields as in <a href="#nft_expr_ops">its definition</a>. Use <code>init</code>, <code>clone</code>, <code>destroy</code> to initialize, clone and destroy object. In <code>init</code>, read attributes from netlink and setup operation’s struct. Implement the core function of this operation in <code>eval</code>, tell kernel what to do by setting <code>regs-&gt;verdict.code</code>. In <code>dump</code>, send the attributes through netlink. Apply constraints to operations in <code>validate</code>.</p>
<p>Create an instance of <code>struct nft_expr_type</code> for your expression. Implements its fields as in <a href="#nft_expr_type">its definition</a>. If you have multiple operations that should be selected dynamically, implement <code>select_ops</code> otherwise set <code>ops</code>. Set <code>name</code>, <code>owner</code> according to your expression. If applicable, set address family at <code>family</code>. If applicable, use <code>flags</code> to indicate if your expression is stateful. Create an array of <code>struct nla_policy</code>, setup attribute information in that array, and set this array as <code>policy</code>. Set <code>maxattr</code> as the maximum number of attributes.</p>
<p>Call <code>nft_register_expr</code> to register your expression. Call <code>nft_unregister_expr</code> to unregister your expression.</p>
<h1 id="Writing-our-own-kernel-code"><a href="#Writing-our-own-kernel-code" class="headerlink" title="Writing our own kernel code"></a>Writing our own kernel code</h1><p>With the knowledge on how to write kernel codes, we are ready to write our own module to add our expression. Here we call our expression “abcde”</p>
<p>abcde.h:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">ifndef</span> _ABCDE_H</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> _ABCDE_H</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">enum</span> <span class="title">nft_abcde_attributes</span> &#123;</span></span><br><span class="line">	NFTA_ABCDE_UNSPEC,</span><br><span class="line">	NFTA_ABCDE_TEXT,</span><br><span class="line">	__NFTA_ABCDE_MAX,</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> NFTA_ABCDE_MAX (__NFTA_ABCDE_MAX - 1)</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span> <span class="comment">/* _ABCDE_H */</span></span></span><br></pre></td></tr></table></figure>

<p>abcde.c:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;net/netfilter/nf_tables.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;linux/tcp.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&quot;abcde.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> ABCDE_TEXT_SIZE 128</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">nft_abcde</span> &#123;</span></span><br><span class="line">	<span class="keyword">char</span> text[ABCDE_TEXT_SIZE];</span><br><span class="line">	<span class="keyword">int</span> len;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">inline</span> <span class="keyword">bool</span> <span class="title">match_packet</span><span class="params">(struct nft_abcde *priv, struct sk_buff *skb)</span> </span>&#123;</span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">tcphdr</span> *<span class="title">tcph</span> =</span> tcp_hdr(skb);</span><br><span class="line">	<span class="keyword">char</span> *user_data = (<span class="keyword">char</span> *)((<span class="keyword">char</span> *)tcph + (tcph-&gt;doff * <span class="number">4</span>));</span><br><span class="line">	<span class="keyword">char</span> *tail = skb_tail_pointer(skb);</span><br><span class="line">	<span class="keyword">char</span> *p;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">for</span> (p = user_data; p &lt; tail - priv-&gt;len; p++) &#123;</span><br><span class="line">		<span class="keyword">int</span> i; <span class="keyword">bool</span> found = <span class="literal">true</span>;</span><br><span class="line">		<span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; priv-&gt;len; i++)</span><br><span class="line">			<span class="keyword">if</span> (p[i] != priv-&gt;text[i]) &#123;</span><br><span class="line">				found = <span class="literal">false</span>;</span><br><span class="line">				<span class="keyword">break</span>;</span><br><span class="line">			&#125;</span><br><span class="line">		<span class="keyword">if</span> (found)</span><br><span class="line">			<span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">nla_policy</span> <span class="title">nft_abcde_policy</span>[<span class="title">NFTA_ABCDE_MAX</span> + 1] =</span> &#123;</span><br><span class="line">	[NFTA_ABCDE_TEXT]		= &#123; .type = NLA_STRING, .len = ABCDE_TEXT_SIZE &#125;,</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">nft_abcde_eval</span><span class="params">(<span class="keyword">const</span> struct nft_expr *expr, struct nft_regs *regs, <span class="keyword">const</span> struct nft_pktinfo *pkt)</span> </span>&#123;</span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">nft_abcde</span> *<span class="title">priv</span> =</span> nft_expr_priv(expr);</span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">sk_buff</span> *<span class="title">skb</span> =</span> pkt-&gt;skb;</span><br><span class="line">	<span class="keyword">if</span>(match_packet(priv, skb))</span><br><span class="line">		regs-&gt;verdict.code = NFT_CONTINUE;</span><br><span class="line">	<span class="keyword">else</span></span><br><span class="line">		regs-&gt;verdict.code = NFT_BREAK;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> <span class="title">nft_abcde_init</span><span class="params">(<span class="keyword">const</span> struct nft_ctx *ctx, <span class="keyword">const</span> struct nft_expr *expr, <span class="keyword">const</span> struct nlattr * <span class="keyword">const</span> tb[])</span> </span>&#123;</span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">nft_abcde</span> *<span class="title">priv</span> =</span> nft_expr_priv(expr);</span><br><span class="line">	<span class="keyword">if</span> (tb[NFTA_ABCDE_TEXT] == <span class="literal">NULL</span>)</span><br><span class="line">		<span class="keyword">return</span> -EINVAL;</span><br><span class="line">	nla_strlcpy(priv-&gt;text, tb[NFTA_ABCDE_TEXT], ABCDE_TEXT_SIZE);</span><br><span class="line">	priv-&gt;len = <span class="built_in">strlen</span>(priv-&gt;text);</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> <span class="title">nft_abcde_dump</span><span class="params">(struct sk_buff *skb, <span class="keyword">const</span> struct nft_expr *expr)</span> </span>&#123;</span><br><span class="line">	<span class="keyword">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">nft_abcde</span> *<span class="title">priv</span> =</span> nft_expr_priv(expr);</span><br><span class="line">	<span class="keyword">if</span> (nla_put_string(skb, NFTA_ABCDE_TEXT, priv-&gt;text))</span><br><span class="line">		<span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">static</span> <span class="class"><span class="keyword">struct</span> <span class="title">nft_expr_type</span> <span class="title">nft_abcde_type</span>;</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">nft_expr_ops</span> <span class="title">nft_abcde_op</span> =</span> &#123;</span><br><span class="line">	.eval = nft_abcde_eval,</span><br><span class="line">	.size = <span class="keyword">sizeof</span>(struct nft_abcde),</span><br><span class="line">	.init = nft_abcde_init,</span><br><span class="line">	.dump = nft_abcde_dump,</span><br><span class="line">	.type = &amp;nft_abcde_type,</span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">static</span> <span class="class"><span class="keyword">struct</span> <span class="title">nft_expr_type</span> <span class="title">nft_abcde_type</span> __<span class="title">read_mostly</span> =</span>  &#123;</span><br><span class="line">	.ops = &amp;nft_abcde_op,</span><br><span class="line">	.name = <span class="string">&quot;abcde&quot;</span>,</span><br><span class="line">	.owner = THIS_MODULE,</span><br><span class="line">	.policy = nft_abcde_policy,</span><br><span class="line">	.maxattr = NFTA_ABCDE_MAX,</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> __init <span class="title">nft_abcde_module_init</span><span class="params">(<span class="keyword">void</span>)</span> </span>&#123;</span><br><span class="line">	<span class="keyword">return</span> nft_register_expr(&amp;nft_abcde_type);</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> __exit <span class="title">nft_abcde_module_exit</span><span class="params">(<span class="keyword">void</span>)</span> </span>&#123;</span><br><span class="line">	nft_unregister_expr(&amp;nft_abcde_type);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">module_init(nft_abcde_module_init);</span><br><span class="line">module_exit(nft_abcde_module_exit);</span><br><span class="line"></span><br><span class="line">MODULE_AUTHOR(<span class="string">&quot;Xiang Gao&quot;</span>);</span><br><span class="line">MODULE_LICENSE(<span class="string">&quot;GPL&quot;</span>);</span><br><span class="line">MODULE_DESCRIPTION(<span class="string">&quot;A sample nftables expression.&quot;</span>);</span><br></pre></td></tr></table></figure>

<p>Makefile:</p>
<figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">obj-m = abcde.o</span><br><span class="line">KVERSION = <span class="variable">$(<span class="built_in">shell</span> uname -r)</span></span><br><span class="line"><span class="section">all:</span></span><br><span class="line">	make -C /lib/modules/<span class="variable">$(KVERSION)</span>/build M=<span class="variable">$(PWD)</span> modules</span><br><span class="line"><span class="section">clean:</span></span><br><span class="line">	make -C /lib/modules/<span class="variable">$(KVERSION)</span>/build M=<span class="variable">$(PWD)</span> clean</span><br></pre></td></tr></table></figure>

<p>The complete source code for this example can be found at GitHub:<br><a target="_blank" rel="noopener" href="https://github.com/zasdfgbnm/nftables-abcde">https://github.com/zasdfgbnm/nftables-abcde</a></p>
<h1 id="Modify-user-space-tool"><a href="#Modify-user-space-tool" class="headerlink" title="Modify user space tool"></a>Modify user space tool</h1><p>In order to be able to conveniently use our new expression “abcde”,  it would be good to modify the source code of user space tool, i.e. the <code>nft</code> command, to make it aware of our new expression. Extending the user space tool is easier. We first check it out from its git repository and switch to tag v0.7 (the newest release when this article is written):</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">clone</span> git://git.netfilter.org/nftables</span><br><span class="line"><span class="built_in">cd</span> nftables</span><br><span class="line">git checkout v0.7 -b abcde</span><br></pre></td></tr></table></figure>

<p>To figure out where to modify, let’s run <code>grep</code> to see how the expression <code>reject</code> is implemented:</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">grep -i reject -r src include</span><br></pre></td></tr></table></figure>
<p>The above command will output something like:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">src&#x2F;datatype.c:         SYMBOL(&quot;reject-route&quot;,          ICMPV6_REJECT_ROUTE),</span><br><span class="line">......</span><br><span class="line">src&#x2F;evaluate.c:static int reject_payload_gen_dependency_tcp(struct eval_ctx *ctx,</span><br><span class="line">......</span><br><span class="line">src&#x2F;netlink_delinearize.c:static void netlink_parse_reject(struct netlink_parse_ctx *ctx,</span><br><span class="line">......</span><br><span class="line">src&#x2F;parser_bison.y:%token _REJECT                       &quot;reject&quot;</span><br><span class="line">......</span><br><span class="line">src&#x2F;scanner.l:&quot;reject&quot;          &#123; return _REJECT; &#125;</span><br><span class="line">src&#x2F;statement.c:static void reject_stmt_print(const struct stmt *stmt)</span><br><span class="line">......</span><br><span class="line">include&#x2F;linux&#x2F;netfilter&#x2F;nf_tables.h: * enum nft_reject_types - nf_tables reject expression reject types</span><br><span class="line">......</span><br><span class="line">include&#x2F;statement.h:struct reject_stmt &#123;</span><br><span class="line">......</span><br></pre></td></tr></table></figure>
<p>This tells us the files we may want to modify. A good start point is <code>scanner.l</code> and <code>parser_bison.y</code>. We can copy and paste the code for reject, replace it with our own thing.</p>
<p>After some try and error, we end up with the following patch generated by <code>git diff v0.7</code>:</p>
<figure class="highlight diff"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">diff --git a/include/statement.h b/include/statement.h</span></span><br><span class="line"><span class="comment">index 277ff2f..9043790 100644</span></span><br><span class="line"><span class="comment">--- a/include/statement.h</span></span><br><span class="line"><span class="comment">+++ b/include/statement.h</span></span><br><span class="line"><span class="meta">@@ -76,6 +76,12 @@</span> struct reject_stmt &#123;</span><br><span class="line"></span><br><span class="line"> extern struct stmt *reject_stmt_alloc(const struct location *loc);</span><br><span class="line"></span><br><span class="line"><span class="addition">+struct abcde_stmt &#123;</span></span><br><span class="line"><span class="addition">+	const char *	text;</span></span><br><span class="line"><span class="addition">+&#125;;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+extern struct stmt *abcde_stmt_alloc(const struct location *loc);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"> struct nat_stmt &#123;</span><br><span class="line"> 	enum nft_nat_types	type;</span><br><span class="line"> 	struct expr		*addr;</span><br><span class="line"><span class="meta">@@ -199,6 +205,7 @@</span> extern struct stmt *xt_stmt_alloc(const struct location *loc);</span><br><span class="line">  * @STMT_LIMIT:		limit statement</span><br><span class="line">  * @STMT_LOG:		log statement</span><br><span class="line">  * @STMT_REJECT:	REJECT statement</span><br><span class="line"><span class="addition">+ * @STMT_ABCDE:		abcde statement</span></span><br><span class="line">  * @STMT_NAT:		NAT statement</span><br><span class="line">  * @STMT_MASQ:		masquerade statement</span><br><span class="line">  * @STMT_REDIR:		redirect statement</span><br><span class="line"><span class="meta">@@ -222,6 +229,7 @@</span> enum stmt_types &#123;</span><br><span class="line"> 	STMT_LIMIT,</span><br><span class="line"> 	STMT_LOG,</span><br><span class="line"> 	STMT_REJECT,</span><br><span class="line"><span class="addition">+	STMT_ABCDE,</span></span><br><span class="line"> 	STMT_NAT,</span><br><span class="line"> 	STMT_MASQ,</span><br><span class="line"> 	STMT_REDIR,</span><br><span class="line"><span class="meta">@@ -280,6 +288,7 @@</span> struct stmt &#123;</span><br><span class="line"> 		struct log_stmt		log;</span><br><span class="line"> 		struct limit_stmt	limit;</span><br><span class="line"> 		struct reject_stmt	reject;</span><br><span class="line"><span class="addition">+		struct abcde_stmt	abcde;</span></span><br><span class="line"> 		struct nat_stmt		nat;</span><br><span class="line"> 		struct masq_stmt	masq;</span><br><span class="line"> 		struct redir_stmt	redir;</span><br><span class="line"><span class="comment">diff --git a/src/evaluate.c b/src/evaluate.c</span></span><br><span class="line"><span class="comment">index 8a3da54..751d702 100644</span></span><br><span class="line"><span class="comment">--- a/src/evaluate.c</span></span><br><span class="line"><span class="comment">+++ b/src/evaluate.c</span></span><br><span class="line"><span class="meta">@@ -2495,6 +2495,8 @@</span> int stmt_evaluate(struct eval_ctx *ctx, struct stmt *stmt)</span><br><span class="line"> 		return stmt_evaluate_ct(ctx, stmt);</span><br><span class="line"> 	case STMT_LOG:</span><br><span class="line"> 		return stmt_evaluate_log(ctx, stmt);</span><br><span class="line"><span class="addition">+	case STMT_ABCDE:</span></span><br><span class="line"><span class="addition">+		return 0;</span></span><br><span class="line"> 	case STMT_REJECT:</span><br><span class="line"> 		return stmt_evaluate_reject(ctx, stmt);</span><br><span class="line"> 	case STMT_NAT:</span><br><span class="line"><span class="comment">diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c</span></span><br><span class="line"><span class="comment">index cb0f6ac..f8b83a6 100644</span></span><br><span class="line"><span class="comment">--- a/src/netlink_delinearize.c</span></span><br><span class="line"><span class="comment">+++ b/src/netlink_delinearize.c</span></span><br><span class="line"><span class="meta">@@ -799,6 +799,16 @@</span> static void netlink_parse_reject(struct netlink_parse_ctx *ctx,</span><br><span class="line"> 	ctx-&gt;stmt = stmt;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"><span class="addition">+static void netlink_parse_abcde(struct netlink_parse_ctx *ctx,</span></span><br><span class="line"><span class="addition">+				 const struct location *loc,</span></span><br><span class="line"><span class="addition">+				 const struct nftnl_expr *expr)</span></span><br><span class="line"><span class="addition">+&#123;</span></span><br><span class="line"><span class="addition">+	struct stmt *stmt;</span></span><br><span class="line"><span class="addition">+	stmt = abcde_stmt_alloc(loc);</span></span><br><span class="line"><span class="addition">+	stmt-&gt;abcde.text = xstrdup(nftnl_expr_get_str(expr, NFTNL_EXPR_ABCDE_TEXT));</span></span><br><span class="line"><span class="addition">+	ctx-&gt;stmt = stmt;</span></span><br><span class="line"><span class="addition">+&#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"> static void netlink_parse_nat(struct netlink_parse_ctx *ctx,</span><br><span class="line"> 			      const struct location *loc,</span><br><span class="line"> 			      const struct nftnl_expr *nle)</span><br><span class="line"><span class="meta">@@ -1144,6 +1154,7 @@</span> static const struct &#123;</span><br><span class="line"> 	&#123; .name = &quot;limit&quot;,	.parse = netlink_parse_limit &#125;,</span><br><span class="line"> 	&#123; .name = &quot;range&quot;,	.parse = netlink_parse_range &#125;,</span><br><span class="line"> 	&#123; .name = &quot;reject&quot;,	.parse = netlink_parse_reject &#125;,</span><br><span class="line"><span class="addition">+	&#123; .name = &quot;abcde&quot;,	.parse = netlink_parse_abcde &#125;,</span></span><br><span class="line"> 	&#123; .name = &quot;nat&quot;,	.parse = netlink_parse_nat &#125;,</span><br><span class="line"> 	&#123; .name = &quot;notrack&quot;,	.parse = netlink_parse_notrack &#125;,</span><br><span class="line"> 	&#123; .name = &quot;masq&quot;,	.parse = netlink_parse_masq &#125;,</span><br><span class="line"><span class="comment">diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c</span></span><br><span class="line"><span class="comment">index 0915038..893ae7e 100644</span></span><br><span class="line"><span class="comment">--- a/src/netlink_linearize.c</span></span><br><span class="line"><span class="comment">+++ b/src/netlink_linearize.c</span></span><br><span class="line"><span class="meta">@@ -874,6 +874,18 @@</span> static void netlink_gen_reject_stmt(struct netlink_linearize_ctx *ctx,</span><br><span class="line"> 	nftnl_rule_add_expr(ctx-&gt;nlr, nle);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"><span class="addition">+static void netlink_gen_abcde_stmt(struct netlink_linearize_ctx *ctx,</span></span><br><span class="line"><span class="addition">+				    const struct stmt *stmt)</span></span><br><span class="line"><span class="addition">+&#123;</span></span><br><span class="line"><span class="addition">+	struct nftnl_expr *nle;</span></span><br><span class="line"><span class="addition">+	nle = alloc_nft_expr(&quot;abcde&quot;);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+	if (stmt-&gt;abcde.text != NULL) &#123;</span></span><br><span class="line"><span class="addition">+		nftnl_expr_set_str(nle, NFTNL_EXPR_ABCDE_TEXT, stmt-&gt;abcde.text);</span></span><br><span class="line"><span class="addition">+	&#125;</span></span><br><span class="line"><span class="addition">+	nftnl_rule_add_expr(ctx-&gt;nlr, nle);</span></span><br><span class="line"><span class="addition">+&#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"> static void netlink_gen_nat_stmt(struct netlink_linearize_ctx *ctx,</span><br><span class="line"> 				 const struct stmt *stmt)</span><br><span class="line"> &#123;</span><br><span class="line"><span class="meta">@@ -1200,6 +1212,8 @@</span> static void netlink_gen_stmt(struct netlink_linearize_ctx *ctx,</span><br><span class="line"> 		return netlink_gen_log_stmt(ctx, stmt);</span><br><span class="line"> 	case STMT_REJECT:</span><br><span class="line"> 		return netlink_gen_reject_stmt(ctx, stmt);</span><br><span class="line"><span class="addition">+	case STMT_ABCDE:</span></span><br><span class="line"><span class="addition">+		return netlink_gen_abcde_stmt(ctx, stmt);</span></span><br><span class="line"> 	case STMT_NAT:</span><br><span class="line"> 		return netlink_gen_nat_stmt(ctx, stmt);</span><br><span class="line"> 	case STMT_MASQ:</span><br><span class="line"><span class="comment">diff --git a/src/parser_bison.y b/src/parser_bison.y</span></span><br><span class="line"><span class="comment">index deaaf06..ac16c72 100644</span></span><br><span class="line"><span class="comment">--- a/src/parser_bison.y</span></span><br><span class="line"><span class="comment">+++ b/src/parser_bison.y</span></span><br><span class="line"><span class="meta">@@ -399,6 +399,7 @@</span> static void location_update(struct location *loc, struct location *rhs, int n)</span><br><span class="line"> %token RANDOM			&quot;random&quot;</span><br><span class="line"> %token FULLY_RANDOM		&quot;fully-random&quot;</span><br><span class="line"> %token PERSISTENT		&quot;persistent&quot;</span><br><span class="line"><span class="addition">+%token ABCDE			&quot;abcde&quot;</span></span><br><span class="line"></span><br><span class="line"> %token QUEUE			&quot;queue&quot;</span><br><span class="line"> %token QUEUENUM			&quot;num&quot;</span><br><span class="line"><span class="meta">@@ -499,6 +500,8 @@</span> static void location_update(struct location *loc, struct location *rhs, int n)</span><br><span class="line"> %type &lt;val&gt;			set_stmt_op</span><br><span class="line"> %type &lt;stmt&gt;			flow_stmt flow_stmt_alloc</span><br><span class="line"> %destructor &#123; stmt_free($$); &#125;	flow_stmt flow_stmt_alloc</span><br><span class="line"><span class="addition">+%type &lt;stmt&gt;			abcde_stmt abcde_stmt_alloc</span></span><br><span class="line"><span class="addition">+%destructor &#123; stmt_free($$); &#125;	abcde_stmt abcde_stmt_alloc</span></span><br><span class="line"></span><br><span class="line"> %type &lt;expr&gt;			symbol_expr verdict_expr integer_expr variable_expr</span><br><span class="line"> %destructor &#123; expr_free($$); &#125;	symbol_expr verdict_expr integer_expr variable_expr</span><br><span class="line"><span class="meta">@@ -1400,6 +1403,7 @@</span> stmt			:	verdict_stmt</span><br><span class="line"> 			|	limit_stmt</span><br><span class="line"> 			|	quota_stmt</span><br><span class="line"> 			|	reject_stmt</span><br><span class="line"><span class="addition">+			|	abcde_stmt</span></span><br><span class="line"> 			|	nat_stmt</span><br><span class="line"> 			|	queue_stmt</span><br><span class="line"> 			|	ct_stmt</span><br><span class="line"><span class="meta">@@ -1736,6 +1740,21 @@</span> reject_opts		:       /* empty */</span><br><span class="line"> 			&#125;</span><br><span class="line"> 			;</span><br><span class="line"></span><br><span class="line"><span class="addition">+abcde_stmt		:	abcde_stmt_alloc	abcde_opts</span></span><br><span class="line"><span class="addition">+			;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+abcde_stmt_alloc	:	ABCDE</span></span><br><span class="line"><span class="addition">+			&#123;</span></span><br><span class="line"><span class="addition">+				$$ = abcde_stmt_alloc(&amp;@$);</span></span><br><span class="line"><span class="addition">+			&#125;</span></span><br><span class="line"><span class="addition">+			;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+abcde_opts		:	string</span></span><br><span class="line"><span class="addition">+			&#123;</span></span><br><span class="line"><span class="addition">+				$&lt;stmt&gt;0-&gt;abcde.text = $1;</span></span><br><span class="line"><span class="addition">+			&#125;</span></span><br><span class="line"><span class="addition">+			;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"> nat_stmt		:	nat_stmt_alloc	nat_stmt_args</span><br><span class="line"> 			;</span><br><span class="line"></span><br><span class="line"><span class="comment">diff --git a/src/scanner.l b/src/scanner.l</span></span><br><span class="line"><span class="comment">index 625023f..595db76 100644</span></span><br><span class="line"><span class="comment">--- a/src/scanner.l</span></span><br><span class="line"><span class="comment">+++ b/src/scanner.l</span></span><br><span class="line"><span class="meta">@@ -333,6 +333,7 @@</span> addrstring	(&#123;macaddr&#125;|&#123;ip4addr&#125;|&#123;ip6addr&#125;)</span><br><span class="line"> &quot;random&quot;		&#123; return RANDOM; &#125;</span><br><span class="line"> &quot;fully-random&quot;		&#123; return FULLY_RANDOM; &#125;</span><br><span class="line"> &quot;persistent&quot;		&#123; return PERSISTENT; &#125;</span><br><span class="line"><span class="addition">+&quot;abcde&quot;             &#123; return ABCDE; &#125;</span></span><br><span class="line"></span><br><span class="line"> &quot;ll&quot;			&#123; return LL_HDR; &#125;</span><br><span class="line"> &quot;nh&quot;			&#123; return NETWORK_HDR; &#125;</span><br><span class="line"><span class="comment">diff --git a/src/statement.c b/src/statement.c</span></span><br><span class="line"><span class="comment">index e70eb51..29b8015 100644</span></span><br><span class="line"><span class="comment">--- a/src/statement.c</span></span><br><span class="line"><span class="comment">+++ b/src/statement.c</span></span><br><span class="line"><span class="meta">@@ -417,6 +417,28 @@</span> struct stmt *reject_stmt_alloc(const struct location *loc)</span><br><span class="line"> 	return stmt_alloc(loc, &amp;reject_stmt_ops);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"><span class="addition">+static void abcde_stmt_print(const struct stmt *stmt)</span></span><br><span class="line"><span class="addition">+&#123;</span></span><br><span class="line"><span class="addition">+	printf(&quot;abcde \&quot;%s\&quot;&quot;, stmt-&gt;abcde.text);</span></span><br><span class="line"><span class="addition">+&#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+static void abcde_stmt_destroy(struct stmt *stmt)</span></span><br><span class="line"><span class="addition">+&#123;</span></span><br><span class="line"><span class="addition">+	xfree(stmt-&gt;abcde.text);</span></span><br><span class="line"><span class="addition">+&#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+static const struct stmt_ops abcde_stmt_ops = &#123;</span></span><br><span class="line"><span class="addition">+	.type		= STMT_ABCDE,</span></span><br><span class="line"><span class="addition">+	.name		= &quot;abcde&quot;,</span></span><br><span class="line"><span class="addition">+	.print		= abcde_stmt_print,</span></span><br><span class="line"><span class="addition">+	.destroy	= abcde_stmt_destroy,</span></span><br><span class="line"><span class="addition">+&#125;;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+struct stmt *abcde_stmt_alloc(const struct location *loc)</span></span><br><span class="line"><span class="addition">+&#123;</span></span><br><span class="line"><span class="addition">+	return stmt_alloc(loc, &amp;abcde_stmt_ops);</span></span><br><span class="line"><span class="addition">+&#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"> static void print_nf_nat_flags(uint32_t flags)</span><br><span class="line"> &#123;</span><br><span class="line"> 	const char *delim = &quot; &quot;;</span><br></pre></td></tr></table></figure>

<p>Same thing applies to libnftnl, we clone the repository and checkout the tag libnftnl-1.0.7:</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">clone</span> git://git.netfilter.org/libnftnl</span><br><span class="line"><span class="built_in">cd</span> libnftnl</span><br><span class="line">git checkout libnftnl-1.0.7 -b abcde</span><br></pre></td></tr></table></figure>

<p>After some try and error, we end up with the following patch using command <code>git diff libnftnl-1.0.7</code>:</p>
<figure class="highlight diff"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">diff --git a/include/libnftnl/expr.h b/include/libnftnl/expr.h</span></span><br><span class="line"><span class="comment">index 74e986d..26259a7 100644</span></span><br><span class="line"><span class="comment">--- a/include/libnftnl/expr.h</span></span><br><span class="line"><span class="comment">+++ b/include/libnftnl/expr.h</span></span><br><span class="line"><span class="meta">@@ -186,6 +186,10 @@</span> enum &#123;</span><br><span class="line"> 	NFTNL_EXPR_REJECT_CODE,</span><br><span class="line"> &#125;;</span><br><span class="line"></span><br><span class="line"><span class="addition">+enum &#123;</span></span><br><span class="line"><span class="addition">+	NFTNL_EXPR_ABCDE_TEXT	= NFTNL_EXPR_BASE,</span></span><br><span class="line"><span class="addition">+&#125;;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"> enum &#123;</span><br><span class="line"> 	NFTNL_EXPR_QUEUE_NUM	= NFTNL_EXPR_BASE,</span><br><span class="line"> 	NFTNL_EXPR_QUEUE_TOTAL,</span><br><span class="line"><span class="comment">diff --git a/include/linux/netfilter/abcde.h b/include/linux/netfilter/abcde.h</span></span><br><span class="line">new file mode 100644</span><br><span class="line"><span class="comment">index 0000000..eb027a7</span></span><br><span class="line"><span class="comment">--- /dev/null</span></span><br><span class="line"><span class="comment">+++ b/include/linux/netfilter/abcde.h</span></span><br><span class="line"><span class="meta">@@ -0,0 +1,12 @@</span></span><br><span class="line"><span class="addition">+#ifndef _ABCDE_H</span></span><br><span class="line"><span class="addition">+#define _ABCDE_H</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+enum nft_abcde_attributes &#123;</span></span><br><span class="line"><span class="addition">+	NFTA_ABCDE_UNSPEC,</span></span><br><span class="line"><span class="addition">+	NFTA_ABCDE_TEXT,</span></span><br><span class="line"><span class="addition">+	__NFTA_ABCDE_MAX,</span></span><br><span class="line"><span class="addition">+&#125;;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+#define NFTA_ABCDE_MAX (__NFTA_ABCDE_MAX - 1)</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+#endif /* _ABCDE_H */</span></span><br><span class="line"><span class="comment">diff --git a/src/Makefile.am b/src/Makefile.am</span></span><br><span class="line"><span class="comment">index 485a8c4..a9cb87d 100644</span></span><br><span class="line"><span class="comment">--- a/src/Makefile.am</span></span><br><span class="line"><span class="comment">+++ b/src/Makefile.am</span></span><br><span class="line"><span class="meta">@@ -35,6 +35,7 @@</span> libnftnl_la_SOURCES = utils.c		\</span><br><span class="line"> 		      expr/fwd.c	\</span><br><span class="line"> 		      expr/limit.c	\</span><br><span class="line"> 		      expr/log.c	\</span><br><span class="line"><span class="addition">+		      expr/abcde.c	\</span></span><br><span class="line"> 		      expr/lookup.c	\</span><br><span class="line"> 		      expr/dynset.c	\</span><br><span class="line"> 		      expr/immediate.c	\</span><br><span class="line"><span class="comment">diff --git a/src/expr/abcde.c b/src/expr/abcde.c</span></span><br><span class="line">new file mode 100644</span><br><span class="line"><span class="comment">index 0000000..e76abd4</span></span><br><span class="line"><span class="comment">--- /dev/null</span></span><br><span class="line"><span class="comment">+++ b/src/expr/abcde.c</span></span><br><span class="line"><span class="meta">@@ -0,0 +1,183 @@</span></span><br><span class="line"><span class="addition">+#include &lt;stdio.h&gt;</span></span><br><span class="line"><span class="addition">+#include &lt;stdint.h&gt;</span></span><br><span class="line"><span class="addition">+#include &lt;string.h&gt;</span></span><br><span class="line"><span class="addition">+#include &lt;arpa/inet.h&gt;</span></span><br><span class="line"><span class="addition">+#include &lt;errno.h&gt;</span></span><br><span class="line"><span class="addition">+#include &lt;linux/netfilter/nf_tables.h&gt;</span></span><br><span class="line"><span class="addition">+#include &lt;linux/netfilter/abcde.h&gt;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+#include &quot;internal.h&quot;</span></span><br><span class="line"><span class="addition">+#include &lt;libmnl/libmnl.h&gt;</span></span><br><span class="line"><span class="addition">+#include &lt;libnftnl/expr.h&gt;</span></span><br><span class="line"><span class="addition">+#include &lt;libnftnl/rule.h&gt;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+struct nftnl_expr_abcde &#123;</span></span><br><span class="line"><span class="addition">+	const char		*text;</span></span><br><span class="line"><span class="addition">+&#125;;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+static int nftnl_expr_abcde_set(struct nftnl_expr *e, uint16_t type,</span></span><br><span class="line"><span class="addition">+				 const void *data, uint32_t data_len)</span></span><br><span class="line"><span class="addition">+&#123;</span></span><br><span class="line"><span class="addition">+	struct nftnl_expr_abcde *abcde = nftnl_expr_data(e);</span></span><br><span class="line"><span class="addition">+	switch(type)&#123;</span></span><br><span class="line"><span class="addition">+	case NFTNL_EXPR_ABCDE_TEXT:</span></span><br><span class="line"><span class="addition">+		abcde-&gt;text = strdup(data);</span></span><br><span class="line"><span class="addition">+		if (!abcde-&gt;text)</span></span><br><span class="line"><span class="addition">+			return -1;</span></span><br><span class="line"><span class="addition">+		break;</span></span><br><span class="line"><span class="addition">+	&#125;</span></span><br><span class="line"><span class="addition">+	return 0;</span></span><br><span class="line"><span class="addition">+&#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+static const void *</span></span><br><span class="line"><span class="addition">+nftnl_expr_abcde_get(const struct nftnl_expr *e, uint16_t type,</span></span><br><span class="line"><span class="addition">+		      uint32_t *data_len)</span></span><br><span class="line"><span class="addition">+&#123;</span></span><br><span class="line"><span class="addition">+	struct nftnl_expr_abcde *abcde = nftnl_expr_data(e);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+	switch(type) &#123;</span></span><br><span class="line"><span class="addition">+	case NFTNL_EXPR_ABCDE_TEXT:</span></span><br><span class="line"><span class="addition">+		*data_len = strlen(abcde-&gt;text)+1;</span></span><br><span class="line"><span class="addition">+		return abcde-&gt;text;</span></span><br><span class="line"><span class="addition">+	&#125;</span></span><br><span class="line"><span class="addition">+	return NULL;</span></span><br><span class="line"><span class="addition">+&#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+static int nftnl_expr_abcde_cb(const struct nlattr *attr, void *data)</span></span><br><span class="line"><span class="addition">+&#123;</span></span><br><span class="line"><span class="addition">+	const struct nlattr **tb = data;</span></span><br><span class="line"><span class="addition">+	int type = mnl_attr_get_type(attr);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+	if (mnl_attr_type_valid(attr, NFTA_ABCDE_MAX) &lt; 0)</span></span><br><span class="line"><span class="addition">+		return MNL_CB_OK;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+	switch(type) &#123;</span></span><br><span class="line"><span class="addition">+	case NFTNL_EXPR_ABCDE_TEXT:</span></span><br><span class="line"><span class="addition">+		if (mnl_attr_validate(attr, MNL_TYPE_STRING) &lt; 0)</span></span><br><span class="line"><span class="addition">+			abi_breakage();</span></span><br><span class="line"><span class="addition">+		break;</span></span><br><span class="line"><span class="addition">+	&#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+	tb[type] = attr;</span></span><br><span class="line"><span class="addition">+	return MNL_CB_OK;</span></span><br><span class="line"><span class="addition">+&#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+static void</span></span><br><span class="line"><span class="addition">+nftnl_expr_abcde_build(struct nlmsghdr *nlh, const struct nftnl_expr *e)</span></span><br><span class="line"><span class="addition">+&#123;</span></span><br><span class="line"><span class="addition">+	struct nftnl_expr_abcde *abcde = nftnl_expr_data(e);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+	if (e-&gt;flags &amp; (1 &lt;&lt; NFTNL_EXPR_ABCDE_TEXT))</span></span><br><span class="line"><span class="addition">+		mnl_attr_put_strz(nlh, NFTNL_EXPR_ABCDE_TEXT, abcde-&gt;text);</span></span><br><span class="line"><span class="addition">+&#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+static int</span></span><br><span class="line"><span class="addition">+nftnl_expr_abcde_parse(struct nftnl_expr *e, struct nlattr *attr)</span></span><br><span class="line"><span class="addition">+&#123;</span></span><br><span class="line"><span class="addition">+	struct nftnl_expr_abcde *abcde = nftnl_expr_data(e);</span></span><br><span class="line"><span class="addition">+	struct nlattr *tb[NFTA_ABCDE_MAX+1] = &#123;&#125;;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+	if (mnl_attr_parse_nested(attr, nftnl_expr_abcde_cb, tb) &lt; 0)</span></span><br><span class="line"><span class="addition">+		return -1;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+	if (tb[NFTNL_EXPR_ABCDE_TEXT]) &#123;</span></span><br><span class="line"><span class="addition">+		if (abcde-&gt;text)</span></span><br><span class="line"><span class="addition">+			xfree(abcde-&gt;text);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+		abcde-&gt;text = strdup(mnl_attr_get_str(tb[NFTNL_EXPR_ABCDE_TEXT]));</span></span><br><span class="line"><span class="addition">+		if (!abcde-&gt;text)</span></span><br><span class="line"><span class="addition">+			return -1;</span></span><br><span class="line"><span class="addition">+		e-&gt;flags |= (1 &lt;&lt; NFTNL_EXPR_ABCDE_TEXT);</span></span><br><span class="line"><span class="addition">+	&#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+	return 0;</span></span><br><span class="line"><span class="addition">+&#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+static int nftnl_expr_abcde_json_parse(struct nftnl_expr *e, json_t *root,</span></span><br><span class="line"><span class="addition">+					struct nftnl_parse_err *err)</span></span><br><span class="line"><span class="addition">+&#123;</span></span><br><span class="line"><span class="addition">+#ifdef JSON_PARSING</span></span><br><span class="line"><span class="addition">+	const char *text;</span></span><br><span class="line"><span class="addition">+	uint16_t group, qthreshold;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+	text = nftnl_jansson_parse_str(root, &quot;text&quot;, err);</span></span><br><span class="line"><span class="addition">+	if (text != NULL)</span></span><br><span class="line"><span class="addition">+		nftnl_expr_set_str(e, NFTNL_EXPR_ABCDE_TEXT, text);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+	return 0;</span></span><br><span class="line"><span class="addition">+#else</span></span><br><span class="line"><span class="addition">+	errno = EOPNOTSUPP;</span></span><br><span class="line"><span class="addition">+	return -1;</span></span><br><span class="line"><span class="addition">+#endif</span></span><br><span class="line"><span class="addition">+&#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+static int nftnl_expr_abcde_snprintf_default(char *buf, size_t size,</span></span><br><span class="line"><span class="addition">+					   const struct nftnl_expr *e)</span></span><br><span class="line"><span class="addition">+&#123;</span></span><br><span class="line"><span class="addition">+	struct nftnl_expr_abcde *abcde = nftnl_expr_data(e);</span></span><br><span class="line"><span class="addition">+	int ret, offset = 0, len = size;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+	if (e-&gt;flags &amp; (1 &lt;&lt; NFTNL_EXPR_ABCDE_TEXT)) &#123;</span></span><br><span class="line"><span class="addition">+		ret = snprintf(buf, len, &quot;text %s &quot;, abcde-&gt;text);</span></span><br><span class="line"><span class="addition">+		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);</span></span><br><span class="line"><span class="addition">+	&#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+	return offset;</span></span><br><span class="line"><span class="addition">+&#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+static int nftnl_expr_abcde_export(char *buf, size_t size,</span></span><br><span class="line"><span class="addition">+				 const struct nftnl_expr *e, int type)</span></span><br><span class="line"><span class="addition">+&#123;</span></span><br><span class="line"><span class="addition">+	struct nftnl_expr_abcde *abcde = nftnl_expr_data(e);</span></span><br><span class="line"><span class="addition">+	NFTNL_BUF_INIT(b, buf, size);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+	if (e-&gt;flags &amp; (1 &lt;&lt; NFTNL_EXPR_ABCDE_TEXT))</span></span><br><span class="line"><span class="addition">+		nftnl_buf_str(&amp;b, type, abcde-&gt;text, &quot;text&quot;);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+	return nftnl_buf_done(&amp;b);</span></span><br><span class="line"><span class="addition">+&#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+static int</span></span><br><span class="line"><span class="addition">+nftnl_expr_abcde_snprintf(char *buf, size_t len, uint32_t type,</span></span><br><span class="line"><span class="addition">+			uint32_t flags, const struct nftnl_expr *e)</span></span><br><span class="line"><span class="addition">+&#123;</span></span><br><span class="line"><span class="addition">+	switch(type) &#123;</span></span><br><span class="line"><span class="addition">+	case NFTNL_OUTPUT_DEFAULT:</span></span><br><span class="line"><span class="addition">+		return nftnl_expr_abcde_snprintf_default(buf, len, e);</span></span><br><span class="line"><span class="addition">+	case NFTNL_OUTPUT_XML:</span></span><br><span class="line"><span class="addition">+	case NFTNL_OUTPUT_JSON:</span></span><br><span class="line"><span class="addition">+		return nftnl_expr_abcde_export(buf, len, e, type);</span></span><br><span class="line"><span class="addition">+	default:</span></span><br><span class="line"><span class="addition">+		break;</span></span><br><span class="line"><span class="addition">+	&#125;</span></span><br><span class="line"><span class="addition">+	return -1;</span></span><br><span class="line"><span class="addition">+&#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+static void nftnl_expr_abcde_free(const struct nftnl_expr *e)</span></span><br><span class="line"><span class="addition">+&#123;</span></span><br><span class="line"><span class="addition">+	struct nftnl_expr_abcde *abcde = nftnl_expr_data(e);</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+	xfree(abcde-&gt;text);</span></span><br><span class="line"><span class="addition">+&#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+static bool nftnl_expr_abcde_cmp(const struct nftnl_expr *e1,</span></span><br><span class="line"><span class="addition">+				     const struct nftnl_expr *e2)</span></span><br><span class="line"><span class="addition">+&#123;</span></span><br><span class="line"><span class="addition">+	struct nftnl_expr_abcde *l1 = nftnl_expr_data(e1);</span></span><br><span class="line"><span class="addition">+	struct nftnl_expr_abcde *l2 = nftnl_expr_data(e2);</span></span><br><span class="line"><span class="addition">+	return !strcmp(l1-&gt;text, l2-&gt;text);</span></span><br><span class="line"><span class="addition">+&#125;</span></span><br><span class="line"><span class="addition">+</span></span><br><span class="line"><span class="addition">+struct expr_ops expr_ops_abcde = &#123;</span></span><br><span class="line"><span class="addition">+	.name		= &quot;abcde&quot;,</span></span><br><span class="line"><span class="addition">+	.alloc_len	= sizeof(struct nftnl_expr_abcde),</span></span><br><span class="line"><span class="addition">+	.max_attr	= NFTA_ABCDE_MAX,</span></span><br><span class="line"><span class="addition">+	.free		= nftnl_expr_abcde_free,</span></span><br><span class="line"><span class="addition">+	.cmp		= nftnl_expr_abcde_cmp,</span></span><br><span class="line"><span class="addition">+	.set		= nftnl_expr_abcde_set,</span></span><br><span class="line"><span class="addition">+	.get		= nftnl_expr_abcde_get,</span></span><br><span class="line"><span class="addition">+	.parse		= nftnl_expr_abcde_parse,</span></span><br><span class="line"><span class="addition">+	.build		= nftnl_expr_abcde_build,</span></span><br><span class="line"><span class="addition">+	.snprintf	= nftnl_expr_abcde_snprintf,</span></span><br><span class="line"><span class="addition">+	.json_parse	= nftnl_expr_abcde_json_parse,</span></span><br><span class="line"><span class="addition">+&#125;;</span></span><br><span class="line"><span class="comment">diff --git a/src/expr_ops.c b/src/expr_ops.c</span></span><br><span class="line"><span class="comment">index 7a0e1e3..a02878c 100644</span></span><br><span class="line"><span class="comment">--- a/src/expr_ops.c</span></span><br><span class="line"><span class="comment">+++ b/src/expr_ops.c</span></span><br><span class="line"><span class="meta">@@ -33,6 +33,7 @@</span> extern struct expr_ops expr_ops_target;</span><br><span class="line"> extern struct expr_ops expr_ops_dynset;</span><br><span class="line"> extern struct expr_ops expr_ops_hash;</span><br><span class="line"> extern struct expr_ops expr_ops_fib;</span><br><span class="line"><span class="addition">+extern struct expr_ops expr_ops_abcde;</span></span><br><span class="line"></span><br><span class="line"> static struct expr_ops expr_ops_notrack = &#123;</span><br><span class="line"> 	.name	= &quot;notrack&quot;,</span><br><span class="line"><span class="meta">@@ -69,6 +70,7 @@</span> static struct expr_ops *expr_ops[] = &#123;</span><br><span class="line"> 	&amp;expr_ops_hash,</span><br><span class="line"> 	&amp;expr_ops_fib,</span><br><span class="line"> 	&amp;expr_ops_objref,</span><br><span class="line"><span class="addition">+	&amp;expr_ops_abcde,</span></span><br><span class="line"> 	NULL,</span><br><span class="line"> &#125;;</span><br></pre></td></tr></table></figure>

<p>The abcde branch of nftables and libnftnl can be found at GitHub:<br><a target="_blank" rel="noopener" href="https://github.com/zasdfgbnm/nftables/tree/abcde">https://github.com/zasdfgbnm/nftables/tree/abcde</a><br><a target="_blank" rel="noopener" href="https://github.com/zasdfgbnm/libnftnl/tree/abcde">https://github.com/zasdfgbnm/libnftnl/tree/abcde</a></p>
<h1 id="Test"><a href="#Test" class="headerlink" title="Test"></a>Test</h1><p>Our new module can be tested by inserting our module, and then using our self-compiled nft tool to add a rule that looks like:</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">PREFIX=/home/gaoxiang/tmp/test_nftables</span><br><span class="line"><span class="built_in">export</span> LD_LIBRARY_PATH=<span class="variable">$PREFIX</span>/lib</span><br><span class="line"><span class="variable">$PREFIX</span>/sbin/nft add table ip <span class="built_in">test</span></span><br><span class="line"><span class="variable">$PREFIX</span>/sbin/nft add chain <span class="built_in">test</span> <span class="built_in">test</span> \&#123; <span class="built_in">type</span> filter hook postrouting priority 0\; \&#125;</span><br><span class="line"><span class="variable">$PREFIX</span>/sbin/nft add rule ip <span class="built_in">test</span> <span class="built_in">test</span> tcp sport 4000 abcde darkhttpd <span class="built_in">log</span> prefix <span class="string">&quot;darkhttpd___&quot;</span></span><br></pre></td></tr></table></figure>

<p>Open a darkhttpd server, access to it, and the output of <code>dmesg</code> will looks like:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">[ 2427.056229] darkhttpd___IN&#x3D; OUT&#x3D;lo SRC&#x3D;127.0.0.1 DST&#x3D;127.0.0.1 LEN&#x3D;60 TOS&#x3D;0x00 PREC&#x3D;0x00 TTL&#x3D;64 ID&#x3D;0 DF PROTO&#x3D;TCP SPT&#x3D;4000 DPT&#x3D;36840 WINDOW&#x3D;43690 RES&#x3D;0x00 ACK SYN URGP&#x3D;0</span><br><span class="line">[ 2427.094038] darkhttpd___IN&#x3D; OUT&#x3D;lo SRC&#x3D;127.0.0.1 DST&#x3D;127.0.0.1 LEN&#x3D;52 TOS&#x3D;0x00 PREC&#x3D;0x00 TTL&#x3D;64 ID&#x3D;9012 DF PROTO&#x3D;TCP SPT&#x3D;4000 DPT&#x3D;36840 WINDOW&#x3D;357 RES&#x3D;0x00 ACK URGP&#x3D;0</span><br><span class="line">[ 2427.094162] darkhttpd___IN&#x3D; OUT&#x3D;lo SRC&#x3D;127.0.0.1 DST&#x3D;127.0.0.1 LEN&#x3D;269 TOS&#x3D;0x00 PREC&#x3D;0x00 TTL&#x3D;64 ID&#x3D;9013 DF PROTO&#x3D;TCP SPT&#x3D;4000 DPT&#x3D;36840 WINDOW&#x3D;357 RES&#x3D;0x00 ACK PSH URGP&#x3D;0</span><br><span class="line">[ 2427.094216] darkhttpd___IN&#x3D; OUT&#x3D;lo SRC&#x3D;127.0.0.1 DST&#x3D;127.0.0.1 LEN&#x3D;97 TOS&#x3D;0x00 PREC&#x3D;0x00 TTL&#x3D;64 ID&#x3D;9014 DF PROTO&#x3D;TCP SPT&#x3D;4000 DPT&#x3D;36840 WINDOW&#x3D;357 RES&#x3D;0x00 ACK PSH URGP&#x3D;0</span><br><span class="line">[ 2427.361198] darkhttpd___IN&#x3D; OUT&#x3D;lo SRC&#x3D;127.0.0.1 DST&#x3D;127.0.0.1 LEN&#x3D;246 TOS&#x3D;0x00 PREC&#x3D;0x00 TTL&#x3D;64 ID&#x3D;9015 DF PROTO&#x3D;TCP SPT&#x3D;4000 DPT&#x3D;36840 WINDOW&#x3D;372 RES&#x3D;0x00 ACK PSH URGP&#x3D;0</span><br><span class="line">[ 2427.361215] darkhttpd___IN&#x3D; OUT&#x3D;lo SRC&#x3D;127.0.0.1 DST&#x3D;127.0.0.1 LEN&#x3D;258 TOS&#x3D;0x00 PREC&#x3D;0x00 TTL&#x3D;64 ID&#x3D;9016 DF PROTO&#x3D;TCP SPT&#x3D;4000 DPT&#x3D;36840 WINDOW&#x3D;372 RES&#x3D;0x00 ACK PSH URGP&#x3D;0</span><br><span class="line">[ 2475.658088] darkhttpd___IN&#x3D; OUT&#x3D;lo SRC&#x3D;127.0.0.1 DST&#x3D;127.0.0.1 LEN&#x3D;52 TOS&#x3D;0x00 PREC&#x3D;0x00 TTL&#x3D;64 ID&#x3D;9017 DF PROTO&#x3D;TCP SPT&#x3D;4000 DPT&#x3D;36840 WINDOW&#x3D;372 RES&#x3D;0x00 ACK URGP&#x3D;0</span><br><span class="line">[ 2521.747363] darkhttpd___IN&#x3D; OUT&#x3D;lo SRC&#x3D;127.0.0.1 DST&#x3D;127.0.0.1 LEN&#x3D;52 TOS&#x3D;0x00 PREC&#x3D;0x00 TTL&#x3D;64 ID&#x3D;9018 DF PROTO&#x3D;TCP SPT&#x3D;4000 DPT&#x3D;36840 WINDOW&#x3D;372 RES&#x3D;0x00 ACK URGP&#x3D;0</span><br><span class="line">[ 2567.826378] darkhttpd___IN&#x3D; OUT&#x3D;lo SRC&#x3D;127.0.0.1 DST&#x3D;127.0.0.1 LEN&#x3D;52 TOS&#x3D;0x00 PREC&#x3D;0x00 TTL&#x3D;64 ID&#x3D;9019 DF PROTO&#x3D;TCP SPT&#x3D;4000 DPT&#x3D;36840 WINDOW&#x3D;372 RES&#x3D;0x00 ACK URGP&#x3D;0</span><br></pre></td></tr></table></figure>

    </div>

    
    
    
        

  <div class="followme">
    <p>Welcome to my other publishing channels</p>

    <div class="social-list">

        <div class="social-item">
          <a target="_blank" class="social-link" href="https://twitter.com/gaoxiang_ai">
            <span class="icon">
              <i class="fab fa-twitter"></i>
            </span>

            <span class="label">Twitter</span>
          </a>
        </div>

        <div class="social-item">
          <a target="_blank" class="social-link" href="/atom.xml">
            <span class="icon">
              <i class="fa fa-rss"></i>
            </span>

            <span class="label">RSS</span>
          </a>
        </div>
    </div>
  </div>


      <footer class="post-footer">
          <div class="post-tags">
              <a href="/tags/Linux/" rel="tag"># Linux</a>
              <a href="/tags/Kernel/" rel="tag"># Kernel</a>
              <a href="/tags/nftables/" rel="tag"># nftables</a>
              <a href="/tags/network/" rel="tag"># network</a>
              <a href="/tags/netfilter/" rel="tag"># netfilter</a>
          </div>

        


        
    <div class="post-nav">
      <div class="post-nav-item">
    <a href="/2017/07/06/Rademacher%E5%A4%8D%E6%9D%82%E5%BA%A6%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/" rel="prev" title="Rademacher复杂度学习笔记">
      <i class="fa fa-chevron-left"></i> Rademacher复杂度学习笔记
    </a></div>
      <div class="post-nav-item">
    <a href="/2017/12/28/%E6%8A%8Adocker%E9%95%9C%E5%83%8F%E5%BD%93%E4%BD%9C%E6%A1%8C%E9%9D%A2%E7%B3%BB%E7%BB%9F%E6%9D%A5%E7%94%A8/" rel="next" title="把docker镜像当作桌面系统来用">
      把docker镜像当作桌面系统来用 <i class="fa fa-chevron-right"></i>
    </a></div>
    </div>
      </footer>
    
  </article>
  
  
  



          </div>
          
    
  <div class="comments">
    <div id="disqus_thread">
      <noscript>Please enable JavaScript to view the comments powered by Disqus.</noscript>
    </div>
  </div>
  

<script>
  window.addEventListener('tabs:register', () => {
    let { activeClass } = CONFIG.comments;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      let commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }
</script>

        </div>
          
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line toggle-line-first"></span>
    <span class="toggle-line toggle-line-middle"></span>
    <span class="toggle-line toggle-line-last"></span>
  </div>

  <aside class="sidebar">
    <div class="sidebar-inner">

      <ul class="sidebar-nav motion-element">
        <li class="sidebar-nav-toc">
          Table of Contents
        </li>
        <li class="sidebar-nav-overview">
          Overview
        </li>
      </ul>

      <!--noindex-->
      <div class="post-toc-wrap sidebar-panel">
          <div class="post-toc motion-element"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#Introduction"><span class="nav-number">1.</span> <span class="nav-text">Introduction</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#Starting-point-of-kernel-code"><span class="nav-number">2.</span> <span class="nav-text">Starting point of kernel code</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#The-usage-of-kernel-API"><span class="nav-number">3.</span> <span class="nav-text">The usage of kernel API</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#struct-nft-expr-ops"><span class="nav-number">3.1.</span> <span class="nav-text">struct nft_expr_ops</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#struct-nft-expr-type"><span class="nav-number">3.2.</span> <span class="nav-text">struct nft_expr_type</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#Summary-on-kernel-codes"><span class="nav-number">4.</span> <span class="nav-text">Summary on kernel codes</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#Writing-our-own-kernel-code"><span class="nav-number">5.</span> <span class="nav-text">Writing our own kernel code</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#Modify-user-space-tool"><span class="nav-number">6.</span> <span class="nav-text">Modify user space tool</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#Test"><span class="nav-number">7.</span> <span class="nav-text">Test</span></a></li></ol></div>
      </div>
      <!--/noindex-->

      <div class="site-overview-wrap sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
  <p class="site-author-name" itemprop="name">zasdfgbnm</p>
  <div class="site-description" itemprop="description"></div>
</div>
<div class="site-state-wrap motion-element">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/archives/">
        
          <span class="site-state-item-count">11</span>
          <span class="site-state-item-name">posts</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
            <a href="/categories/">
          
        <span class="site-state-item-count">5</span>
        <span class="site-state-item-name">categories</span></a>
      </div>
      <div class="site-state-item site-state-tags">
            <a href="/tags/">
          
        <span class="site-state-item-count">56</span>
        <span class="site-state-item-name">tags</span></a>
      </div>
  </nav>
</div>
  <div class="links-of-author motion-element">
      <span class="links-of-author-item">
        <a href="https://github.com/zasdfgbnm" title="GitHub → https:&#x2F;&#x2F;github.com&#x2F;zasdfgbnm" rel="noopener" target="_blank"><i class="fab fa-github fa-fw"></i>GitHub</a>
      </span>
      <span class="links-of-author-item">
        <a href="https://twitter.com/gaoxiang_ai" title="Twitter → https:&#x2F;&#x2F;twitter.com&#x2F;gaoxiang_ai" rel="noopener" target="_blank"><i class="fab fa-twitter fa-fw"></i>Twitter</a>
      </span>
  </div>



      </div>

    </div>
  </aside>
  <div id="sidebar-dimmer"></div>


      </div>
    </main>

    <footer class="footer">
      <div class="footer-inner">
        

        

<div class="copyright">
  
  &copy; 
  <span itemprop="copyrightYear">2021</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">zasdfgbnm</span>
</div>
  <div class="powered-by">Powered by <a href="https://hexo.io/" class="theme-link" rel="noopener" target="_blank">Hexo</a> & <a href="https://muse.theme-next.org/" class="theme-link" rel="noopener" target="_blank">NexT.Muse</a>
  </div>

        








      </div>
    </footer>
  </div>

  
  <script src="/lib/anime.min.js"></script>
  <script src="/lib/velocity/velocity.min.js"></script>
  <script src="/lib/velocity/velocity.ui.min.js"></script>

<script src="/js/utils.js"></script>

<script src="/js/motion.js"></script>


<script src="/js/schemes/muse.js"></script>


<script src="/js/next-boot.js"></script>




  
  <script>
    (function(){
      var canonicalURL, curProtocol;
      //Get the <link> tag
      var x=document.getElementsByTagName("link");
		//Find the last canonical URL
		if(x.length > 0){
			for (i=0;i<x.length;i++){
				if(x[i].rel.toLowerCase() == 'canonical' && x[i].href){
					canonicalURL=x[i].href;
				}
			}
		}
    //Get protocol
	    if (!canonicalURL){
	    	curProtocol = window.location.protocol.split(':')[0];
	    }
	    else{
	    	curProtocol = canonicalURL.split(':')[0];
	    }
      //Get current URL if the canonical URL does not exist
	    if (!canonicalURL) canonicalURL = window.location.href;
	    //Assign script content. Replace current URL with the canonical URL
      !function(){var e=/([http|https]:\/\/[a-zA-Z0-9\_\.]+\.baidu\.com)/gi,r=canonicalURL,t=document.referrer;if(!e.test(r)){var n=(String(curProtocol).toLowerCase() === 'https')?"https://sp0.baidu.com/9_Q4simg2RQJ8t7jm9iCKT-xh_/s.gif":"//api.share.baidu.com/s.gif";t?(n+="?r="+encodeURIComponent(document.referrer),r&&(n+="&l="+r)):r&&(n+="?l="+r);var i=new Image;i.src=n}}(window);})();
  </script>















  

  

  

<script>
  function loadCount() {
    var d = document, s = d.createElement('script');
    s.src = 'https://zasdfgbnm-github-io.disqus.com/count.js';
    s.id = 'dsq-count-scr';
    (d.head || d.body).appendChild(s);
  }
  // defer loading until the whole page loading is completed
  window.addEventListener('load', loadCount, false);
</script>
<script>
  var disqus_config = function() {
    this.page.url = "https://zasdfgbnm.github.io/2017/09/07/Extending-nftables/";
    this.page.identifier = "2017/09/07/Extending-nftables/";
    this.page.title = "Adding new expressions to nftables";
    };
  NexT.utils.loadComments(document.querySelector('#disqus_thread'), () => {
    if (window.DISQUS) {
      DISQUS.reset({
        reload: true,
        config: disqus_config
      });
    } else {
      var d = document, s = d.createElement('script');
      s.src = 'https://zasdfgbnm-github-io.disqus.com/embed.js';
      s.setAttribute('data-timestamp', '' + +new Date());
      (d.head || d.body).appendChild(s);
    }
  });
</script>

</body>
</html>
